<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

/**
 * Handles the OAuth2 "Authenticate with Google" flow for the Gmail /
 * Google Workspace SMTP connection. The Client ID/Secret are supplied by
 * the user in the connection form (not yet saved), so they are staged in
 * the session for the round trip to Google and back - the tokens are only
 * persisted to the database when the user saves the connection.
 */
class GoogleOAuthController extends Controller
{
    private const SCOPES = 'https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/userinfo.email';

    public function start(Request $request)
    {
        $data = $request->validate([
            'client_id'     => 'required|string|max:255',
            'client_secret' => 'required|string|max:500',
        ]);

        $state = Str::random(40);

        session(["google_oauth.{$state}" => [
            'client_id'     => $data['client_id'],
            'client_secret' => $data['client_secret'],
            'user_id'       => $request->user()->id,
            'created_at'    => now()->timestamp,
        ]]);

        $query = http_build_query([
            'client_id'     => $data['client_id'],
            'redirect_uri'  => route('smtp.google.callback'),
            'response_type' => 'code',
            'access_type'   => 'offline',
            'prompt'        => 'consent',
            'scope'         => self::SCOPES,
            'state'         => $state,
        ]);

        return response()->json([
            'url' => "https://accounts.google.com/o/oauth2/v2/auth?{$query}",
        ]);
    }

    public function callback(Request $request)
    {
        $state = (string) $request->query('state');
        $code  = $request->query('code');
        $error = $request->query('error');

        $key     = "google_oauth.{$state}";
        $pending = $state !== '' ? session($key) : null;
        session()->forget($key);

        if ($error || !$pending || !$code || $pending['user_id'] !== $request->user()?->id
            || (now()->timestamp - $pending['created_at']) > 900) {
            return view('google-oauth-result', [
                'success' => false,
                'message' => $error ? "Google denied access: {$error}" : 'This authentication link has expired or is invalid - please try again.',
            ]);
        }

        try {
            $tokenResponse = Http::asForm()->post('https://oauth2.googleapis.com/token', [
                'code'          => $code,
                'client_id'     => $pending['client_id'],
                'client_secret' => $pending['client_secret'],
                'redirect_uri'  => route('smtp.google.callback'),
                'grant_type'    => 'authorization_code',
            ]);

            $tokens = $tokenResponse->json() ?? [];

            if (!$tokenResponse->successful() || empty($tokens['access_token'])) {
                throw new \RuntimeException($tokens['error_description'] ?? $tokens['error'] ?? 'Google did not return an access token.');
            }

            $userInfo = Http::withToken($tokens['access_token'])
                ->get('https://www.googleapis.com/oauth2/v2/userinfo')
                ->json() ?? [];

            return view('google-oauth-result', [
                'success'      => true,
                'refreshToken' => $tokens['refresh_token'] ?? null,
                'accessToken'  => $tokens['access_token'],
                'expiresAt'    => now()->addSeconds((int) ($tokens['expires_in'] ?? 3600))->toISOString(),
                'googleEmail'  => $userInfo['email'] ?? null,
            ]);
        } catch (\Throwable $e) {
            return view('google-oauth-result', [
                'success' => false,
                'message' => $e->getMessage(),
            ]);
        }
    }
}
