import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import { sql } from "@/db";
import { google } from "@/lib/oauth";
import { logAudit } from "@/lib/audit";

export const dynamic = "force-dynamic";

const APP_URL = process.env.NEXT_PUBLIC_APP_URL || "https://tia.manohargupta.com";

export async function GET(request: Request) {
  const url = new URL(request.url);
  const code = url.searchParams.get("code");
  const state = url.searchParams.get("state");

  const cookieStore = await cookies();
  const storedState = cookieStore.get("g_state")?.value;
  const verifier = cookieStore.get("g_verifier")?.value;

  // 1. CSRF / integrity check — returned state must match what we sent.
  if (!code || !state || !storedState || state !== storedState || !verifier) {
    return NextResponse.redirect(new URL("/login?error=oauth", APP_URL));
  }

  try {
    // 2. Exchange the code for tokens (arctic POSTs to Google).
    const tokens = await google.validateAuthorizationCode(code, verifier);

    // 3. Fetch the verified profile. Calling userinfo directly over TLS
    //    means we don't need to verify an ID-token JWT signature ourselves.
    const profileRes = await fetch(
      "https://openidconnect.googleapis.com/v1/userinfo",
      { headers: { Authorization: `Bearer ${tokens.accessToken()}` } },
    );
    if (!profileRes.ok) {
      return NextResponse.redirect(new URL("/login?error=oauth", APP_URL));
    }
    const profile = (await profileRes.json()) as {
      sub: string; email: string; email_verified: boolean;
      name?: string; picture?: string;
    };

    // 4. HARD requirement: Google must confirm the email is verified.
    if (!profile.email || !profile.email_verified) {
      return NextResponse.redirect(new URL("/login?error=unverified", APP_URL));
    }

    // 5. Find or create the user.
    const existing = await sql`
      SELECT id, password_hash, email_verified FROM users
      WHERE email = ${profile.email} LIMIT 1
    `;
    let userId: string;
    let isNewUser = false;

    if (existing.length === 0) {
      userId = crypto.randomUUID();
      isNewUser = true;
      await sql`
        INSERT INTO users (id, email, name, image, email_verified, created_at, updated_at)
        VALUES (${userId}, ${profile.email}, ${profile.name ?? null},
                ${profile.picture ?? null}, NOW(), NOW(), NOW())
      `;
    } else {
      userId = existing[0].id;
      // LINKING GUARD: a password set on an account that was never
      // email-verified was never proven to belong to this person.
      // Google just proved ownership -> drop that unverified password
      // (kills any pre-registration takeover) and mark verified.
      if (existing[0].password_hash && !existing[0].email_verified) {
        await sql`UPDATE users SET password_hash = NULL, email_verified = NOW() WHERE id = ${userId}`;
      } else if (!existing[0].email_verified) {
        await sql`UPDATE users SET email_verified = NOW() WHERE id = ${userId}`;
      }
    }

    // 6. Record the Google link (identity only — Tia never calls Google
    //    APIs after login, so there are no tokens worth storing).
    //    Relies on the unique index on (provider, provider_account_id).
    await sql`
      INSERT INTO accounts (user_id, type, provider, provider_account_id)
      VALUES (${userId}, 'oidc', 'google', ${profile.sub})
      ON CONFLICT (provider, provider_account_id) DO NOTHING
    `;

    // 7. Mint a tia_session — identical to signin/route.ts.
    const sessionToken = crypto.randomUUID();
    const expires = new Date();
    expires.setDate(expires.getDate() + 30);
    await sql`
      INSERT INTO sessions (session_token, user_id, expires)
      VALUES (${sessionToken}, ${userId}, ${expires.toISOString()})
    `;
    await logAudit({ userId, action: "login", request, metadata: { method: "google" } });

    const response = NextResponse.redirect(
      new URL(isNewUser ? "/onboarding" : "/", APP_URL),
    );
    response.cookies.set("tia_session", sessionToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "lax",
      maxAge: 60 * 60 * 24 * 30,
      path: "/",
    });
    response.cookies.delete("g_state");
    response.cookies.delete("g_verifier");
    return response;
  } catch (e) {
    console.error("Google callback error:", e);
    return NextResponse.redirect(new URL("/login?error=oauth", APP_URL));
  }
}
