<?php

declare(strict_types=1);

namespace Maestro\Core\Http\Controllers\Auth;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;
use Maestro\Core\Http\Controllers\Controller;
use Maestro\Core\Services\MicrosoftAuthService;

/**
 * Microsoft Entra ID OAuth via Laravel Socialite (socialiteproviders/microsoft).
 *
 * @see MicrosoftAuthService Pre-provisioned users only (no JIT).
 */
class MicrosoftAuthController extends Controller
{
    public function __construct(
        protected MicrosoftAuthService $microsoftAuth,
    ) {}

    public function redirect(Request $request): RedirectResponse
    {
        if (! $this->microsoftSsoConfigured()) {
            return $this->redirectToLoginWithError('Microsoft sign-in is not configured.');
        }

        try {
            $scopes = config('services.microsoft.graph_scopes', 'openid profile email offline_access User.Read');
            $scopeArray = is_string($scopes) ? explode(' ', $scopes) : $scopes;

            return Socialite::driver('microsoft')
                ->scopes($scopeArray)
                ->redirect();
        } catch (\Throwable $e) {
            Log::error('Microsoft OAuth redirect failed', [
                'message' => $e->getMessage(),
            ]);

            return $this->redirectToLoginWithError('Failed to initiate Microsoft login. Please try again.');
        }
    }

    public function callback(Request $request): RedirectResponse
    {
        if (! $this->microsoftSsoConfigured()) {
            return $this->redirectToLoginWithError('Microsoft sign-in is not configured.');
        }

        $error = $request->query('error');
        if ($error) {
            Log::warning('Microsoft OAuth callback error', [
                'error' => $error,
                'error_description' => $request->query('error_description'),
            ]);

            return $this->redirectToLoginWithError('Microsoft login failed. Please try again.');
        }

        try {
            $microsoftUser = Socialite::driver('microsoft')->user();
            $oid = $microsoftUser->getId();
            $email = $microsoftUser->getEmail();

            if (! $oid) {
                Log::warning('Microsoft OAuth: missing user ID', ['email' => $email]);

                return $this->redirectToLoginWithError('Could not complete sign-in. Please try again.');
            }

            $user = $this->microsoftAuth->findUserByMicrosoftId((string) $oid);
            if ($user === null) {
                Log::info('Microsoft SSO: access denied – user not in application', [
                    'microsoft_user_id' => $oid,
                    'email' => $email,
                ]);

                return $this->redirectToAccessDenied('No access to the application. Contact your administrator.');
            }

            $request->session()->regenerate();
            Auth::guard('web')->login($user, remember: true);

            activity('users')
                ->causedBy($user)
                ->performedOn($user)
                ->event('login_microsoft')
                ->withProperties([
                    'ip' => $request->ip(),
                    'user_agent' => $request->userAgent(),
                ])
                ->log('User signed in with Microsoft');

            return redirect()->away($this->frontendBaseUrl().'/');
        } catch (\Throwable $e) {
            Log::warning('Microsoft OAuth callback exception', [
                'message' => $e->getMessage(),
            ]);

            return $this->redirectToLoginWithError('Could not complete sign-in. Please try again.');
        }
    }

    private function microsoftSsoConfigured(): bool
    {
        $id = config('services.microsoft.client_id');
        $secret = config('services.microsoft.client_secret');
        $redirect = config('services.microsoft.redirect');

        return is_string($id) && $id !== ''
            && is_string($secret) && $secret !== ''
            && is_string($redirect) && $redirect !== '';
    }

    private function redirectToLoginWithError(string $message): RedirectResponse
    {
        return redirect()->away($this->frontendBaseUrl().'/auth/login?error='.urlencode($message));
    }

    private function redirectToAccessDenied(string $message): RedirectResponse
    {
        return redirect()->away($this->frontendBaseUrl().'/auth/access?message='.urlencode($message));
    }

    private function frontendBaseUrl(): string
    {
        return rtrim((string) config('services.microsoft.frontend_url', config('app.url', 'http://localhost')), '/');
    }
}
