<?php

namespace App\Services;

use App\Models\DiscordLog;
use App\Models\DiscordRoleMap;
use App\Models\User;
use Illuminate\Support\Facades\Http;

class DiscordRoleSyncService
{
    /**
     * Reads the user's current Discord guild roles (via the bot token —
     * avoids depending on the user's OAuth access token still being valid)
     * and syncs their local Spatie roles to match the configured mapping
     * in `discord_role_maps`. Users always keep the base "player" role;
     * mapped roles are added/removed, but roles with no corresponding
     * Discord mapping row (e.g. a role granted manually by a superadmin)
     * are left untouched.
     */
    public function syncForUser(User $user): void
    {
        if (! $user->discord_id) {
            return;
        }

        $guildId = config('services.discord.guild_id');
        $botToken = config('services.discord.bot_token');

        $response = Http::withToken($botToken, 'Bot')
            ->get("https://discord.com/api/v10/guilds/{$guildId}/members/{$user->discord_id}");

        if ($response->failed()) {
            DiscordLog::record('role_sync_failed', "Failed to fetch Discord member for {$user->name}", [
                'user_id' => $user->id,
                'status' => $response->status(),
            ]);

            return;
        }

        $discordRoleIds = $response->json('roles', []);

        $maps = DiscordRoleMap::query()->whereIn('discord_role_id', $discordRoleIds)->get();
        $managedRoleNames = DiscordRoleMap::query()->pluck('spatie_role_name')->unique();

        $newRoles = $maps->pluck('spatie_role_name')->unique();
        $keptRoles = collect($user->getRoleNames())->diff($managedRoleNames);

        $user->syncRoles($keptRoles->merge($newRoles)->push('player')->unique());

        DiscordLog::record('role_sync', "Synced Discord roles for {$user->name}", [
            'user_id' => $user->id,
            'roles' => $newRoles->values(),
        ]);
    }
}
