<?php

namespace App\Http\Controllers;

use App\Domain\Shared\Services\SocialAccountService;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;

class SocialAuthController extends Controller
{
    public function __construct(private readonly SocialAccountService $socialAccountService) {}

    public function redirect(string $provider): RedirectResponse
    {
        $this->validateProvider($provider);

        $driver = Socialite::driver($provider);

        // Enable PKCE for providers that support it (X has it on by default)
        if (in_array($provider, config('social.pkce_providers', []), true)) {
            $driver->enablePKCE();
        }

        return $driver->redirect();
    }

    public function callback(Request $request, string $provider): RedirectResponse
    {
        $this->validateProvider($provider);

        try {
            $driver = Socialite::driver($provider);

            if (in_array($provider, config('social.pkce_providers', []), true)) {
                $driver->enablePKCE();
            }

            $socialUser = $driver->user();
        } catch (\Throwable $e) {
            // Pass the Throwable itself (not just the message) so Sentry captures
            // the class + stacktrace for grouping — the message-only form left
            // these undiagnosable (#826).
            Log::error('Social login callback failed', [
                'provider' => $provider,
                'exception' => $e,
            ]);

            return redirect()->route('login')
                ->withErrors(['social' => 'Authentication failed. Please try again.']);
        }

        return $this->processCallback($request, $provider, $socialUser);
    }

    /**
     * Apple uses response_mode=form_post — callback arrives as POST.
     * Route must bypass CSRF verification.
     */
    public function appleCallback(Request $request): RedirectResponse
    {
        try {
            $socialUser = Socialite::driver('apple')->user();
        } catch (\Throwable $e) {
            // The Apple form_post POST path previously failed SILENTLY (no log at
            // all), so real Apple Sign In failures were invisible in Sentry and
            // the file log. Capture the exception so the cause is diagnosable.
            Log::error('Apple Sign In callback failed', [
                'exception' => $e,
            ]);

            return redirect()->route('login')
                ->withErrors(['social' => 'Apple Sign In failed. Please try again.']);
        }

        return $this->processCallback($request, 'apple', $socialUser);
    }

    public function linkRedirect(string $provider): RedirectResponse
    {
        $this->validateProvider($provider);

        $driver = Socialite::driver($provider);

        if (in_array($provider, config('social.pkce_providers', []), true)) {
            $driver->enablePKCE();
        }

        return $driver->redirect();
    }

    public function unlink(string $provider): RedirectResponse
    {
        $this->validateProvider($provider);

        $success = $this->socialAccountService->unlink(Auth::user(), $provider);

        if (! $success) {
            return redirect()->route('team.settings')
                ->withErrors(['social' => 'Cannot disconnect your only login method. Set a password first.']);
        }

        return redirect()->route('team.settings')
            ->with('status', ucfirst($provider).' account disconnected.');
    }

    public function storeEmail(Request $request): RedirectResponse
    {
        $request->validate(['email' => ['required', 'email', 'max:255']]);

        // Guard: email already registered — do not auto-link without verification.
        // The email here is user-supplied and unverified (the provider returned none).
        // Linking to an existing account without ownership proof would allow account takeover.
        if (User::where('email', $request->input('email'))->exists()) {
            return back()->withErrors(['email' => 'An account with this email already exists. Please log in and connect your social account from Settings.']);
        }

        $user = $this->socialAccountService->completePendingRegistration($request->input('email'));

        if (! $user) {
            return redirect()->route('login')
                ->withErrors(['social' => 'Session expired. Please try again.']);
        }

        // Regenerate session to prevent session fixation after privilege change.
        $request->session()->regenerate();
        Auth::login($user, remember: true);

        return redirect()->intended(route('dashboard'));
    }

    private function processCallback(Request $request, string $provider, \Laravel\Socialite\Contracts\User $socialUser): RedirectResponse
    {
        $result = $this->socialAccountService->handleCallback($provider, $socialUser);

        if ($result['redirect']) {
            return redirect($result['redirect']);
        }

        if ($result['user']) {
            // Regenerate session to prevent session fixation after privilege change.
            $request->session()->regenerate();
            Auth::login($result['user'], remember: true);

            return redirect()->intended(route('dashboard'));
        }

        return redirect()->route('login')
            ->withErrors(['social' => 'Something went wrong. Please try again.']);
    }

    private function validateProvider(string $provider): void
    {
        if (! in_array($provider, config('social.providers', []), true)) {
            abort(404);
        }
    }
}
