<?php

namespace App\Http\Controllers\Auth;

use App\Enums\UserRole;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;

class DiscordAuthController extends Controller
{
    /**
     * Redirect to Discord
     */
    public function redirect(): RedirectResponse
    {
        return Socialite::driver('discord')->redirect();
    }

    /**
     * Callback received from Discord
     */
    public function callback(): RedirectResponse
    {
        $discordUser = Socialite::driver('discord')->user();

        $user = User::where('discord_id', $discordUser->id)->first();

        if (! $user) {
            // link by email if it already exists
            $user = User::where('email', $discordUser->email)->first();

            if ($user) {
                $user->update([
                    'discord_id' => $discordUser->id,
                    'discord_avatar' => $discordUser->avatar,
                ]);
            } else {
                // Create new user
                $user = User::create([
                    'name' => $discordUser->name,
                    'email' => $discordUser->email,
                    'discord_id' => $discordUser->id,
                    'discord_avatar' => $discordUser->avatar,
                    'password' => null,
                ]);
            }
        }

        $this->checkDiscordAvatar($discordUser, $user);
        $this->checkDiscordRoles($user);

        Auth::login($user, true);

        return redirect()->route('home.index');
    }

    /**
     * Check if discord avatar changed
     */
    private function checkDiscordAvatar(\Laravel\Socialite\Contracts\User $socialiteUser, User $user): void
    {
        if ($socialiteUser->avatar != $user->discord_avatar) {
            $user->update(['discord_avatar' => $socialiteUser->avatar]);
        }
    }

    /**
     * Check Discord Roles if user is Patreon member
     */
    private function checkDiscordRoles(User $user): void
    {
        // Should not ever happen
        if (! $user->discord_id) {
            return;
        }

        $guildId = config('discord.guild_id');

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

        // User is not in the guild
        if ($response->status() === 404) {
            $user->removeRole(UserRole::SUPPORTER);

            return;
        }

        // Something else failed
        if ($response->failed()) {
            Log::warning('Discord role check failed', [
                'user_id' => $user->id,
                'discord_id' => $user->discord_id,
                'status' => $response->status(),
                'body' => $response->body(),
            ]);

            return;
        }

        $discordRoles = $response->json('roles', []);
        $patreonRoles = config('discord.patreon_roles', []);

        // If intersect of array is empty, then the user doesn't have the role
        $hasSupporterRole = ! empty(array_intersect($discordRoles, $patreonRoles));

        if (! $hasSupporterRole) {
            // Remove role if not found
            $user->removeRole(UserRole::SUPPORTER);

            return;
        }

        $user->addRole(UserRole::SUPPORTER);
    }
}
