<?php

declare(strict_types=1);

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\Role;
use App\Models\User;
use App\Services\ActivityLogger;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;

final class SocialiteController extends Controller
{
    /**
     * Redirect the user to the Azure AD authentication page.
     * Logs the Azure config (client_id prefix, redirect URI, tenant) and generated redirect URL.
     */
    public function redirect(): RedirectResponse
    {
        $azureConfig = config('services.azure');

        Log::info('[Azure SSO] Initiating redirect', [
            'client_id_prefix' => substr((string) Arr::get($azureConfig, 'client_id', ''), 0, 4),
            'redirect_uri' => Arr::get($azureConfig, 'redirect'),
            'tenant' => Arr::get($azureConfig, 'tenant'),
        ]);

        $response = Socialite::driver('azure')->redirect();

        Log::info('[Azure SSO] Redirect URL generated', [
            'redirect_url' => $response->getTargetUrl(),
        ]);

        return $response;
    }

    /**
     * Handle the callback from Azure AD after authentication.
     * Logs request parameters, the resolved Azure user, and the upserted local user.
     * Wraps the entire flow in a try/catch to capture and log any exceptions.
     */
    public function callback(): RedirectResponse
    {
        try {
            return $this->processCallback();
        } catch (\Throwable $e) {
            Log::error('[Azure SSO] Exception during callback', [
                'message' => $e->getMessage(),
                'exception' => $e->getTraceAsString(),
            ]);

            throw $e;
        }
    }

    /**
     * Log the user out and redirect to landing page.
     */
    public function logout(Request $request): RedirectResponse
    {
        ActivityLogger::log('logout', auth()->id());

        auth()->logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        return redirect('/');
    }

    /**
     * Execute the full Azure AD callback flow: resolve the user, upsert the local record,
     * assign a default role if needed, log the user in, and record the activity.
     */
    private function processCallback(): RedirectResponse
    {
        Log::info('[Azure SSO] Callback received', [
            'query_code' => substr((string) request()->query('code', ''), 0, 8).'…',
            'query_state' => request()->query('state'),
            'query_error' => request()->query('error'),
            'query_error_description' => request()->query('error_description'),
        ]);

        $azureUser = Socialite::driver('azure')->user();

        Log::info('[Azure SSO] Azure user resolved', [
            'azure_id' => $azureUser->getId(),
            'email' => $azureUser->getEmail(),
            'name' => $azureUser->getName(),
            'job_title' => Arr::get($azureUser->user, 'jobTitle'),
            'department' => Arr::get($azureUser->user, 'department'),
            'company' => Arr::get($azureUser->user, 'companyName'),
        ]);

        $user = User::query()->updateOrCreate(
            ['email' => $azureUser->getEmail()],
            [
                'name' => $azureUser->getName(),
                'azure_id' => $azureUser->getId(),
                'photo' => $azureUser->getAvatar(),
                'job_title' => Arr::get($azureUser->user, 'jobTitle'),
                'department' => Arr::get($azureUser->user, 'department'),
                'company_name' => Arr::get($azureUser->user, 'companyName'),
                'phone' => Arr::get($azureUser->user, 'mobilePhone', Arr::get($azureUser->user, 'businessPhones.0')),
            ]
        );

        Log::info('[Azure SSO] Local user upserted', [
            'user_id' => $user->id,
            'email' => $user->email,
            'was_recent' => $user->wasRecentlyCreated,
            'role_id' => $user->role_id,
        ]);

        if ($user->role_id === null) {
            $user->update(['role_id' => Role::where('name', 'user')->first()->id]);

            Log::info('[Azure SSO] Default role assigned', [
                'user_id' => $user->id,
                'role_id' => $user->role_id,
            ]);
        }

        auth()->login($user);

        ActivityLogger::log('login', $user->id, metadata: ['email' => $user->email, 'firm_name' => Arr::get($azureUser->user, 'companyName')]);

        return redirect('/');
    }
}
