import { cookies } from 'next/headers'
import { NextRequest } from 'next/server'
import { z } from 'zod'
import { createGoogleOAuthClient, googleContextCookie, safeNextPath, type GoogleContext } from '@/lib/auth/google-oauth'
import { listEnvUsers, findEnvUserById, type EnvUser } from '@/lib/auth/env-users'
import { effectiveRole, getAccountOverride } from '@/lib/auth/accounts'
import { effectiveIdentity } from '@/lib/domain/account'
import { ensureSelfAccount, findSelfAccountByEmail, findSelfAccountById, selfAccountAsEnvUser } from '@/lib/auth/self-accounts'
import { findAppAccountBySupabaseUserId, linkAppAccountToSupabaseUser } from '@/lib/auth/google-account-link'
import { establishSession } from '@/lib/auth/establish-session'
import { setMfaPendingCookie } from '@/lib/auth/session'
import { mfaEnabledFor } from '@/lib/security/mfa'
import { createAdminClient } from '@/lib/supabase/admin'
import { emailPattern } from '@/lib/like'
import { logSecurityEvent } from '@/lib/security/events'
import { clientIp } from '@/lib/security/rate-limit'
import { sameSiteRedirect } from '@/lib/app-url'

const contextSchema = z.object({
  mode: z.enum(['login', 'signup']),
  role: z.enum(['broker', 'dispatcher', 'driver']),
  company: z.string().max(120),
  next: z.string().nullable(),
})

function errorRedirect(mode: 'login' | 'signup', reason: string) {
  return sameSiteRedirect(`${mode === 'signup' ? '/signup' : '/login'}?google_error=${reason}`)
}

export async function GET(req: NextRequest) {
  const jar = await cookies()
  const flowId = req.nextUrl.searchParams.get('sb_flow_id') ?? ''
  const contextCookie = googleContextCookie(flowId)
  if (!contextCookie) return errorRedirect('login', 'expired')
  let raw: unknown = null
  try { raw = JSON.parse(jar.get(contextCookie)?.value || 'null') } catch { /* invalid cookie */ }
  const parsed = contextSchema.safeParse(raw)
  jar.delete(contextCookie)
  if (!parsed.success) return errorRedirect('login', 'expired')
  const context: GoogleContext = { ...parsed.data, next: safeNextPath(parsed.data.next) }
  const code = req.nextUrl.searchParams.get('code')
  if (!code) return errorRedirect(context.mode, 'cancelled')

  try {
    const supabase = await createGoogleOAuthClient()
    const { data, error } = await supabase.auth.exchangeCodeForSession(code, { flowId })
    const identity = data.user?.identities?.some((entry) => entry.provider === 'google')
    const email = data.user?.email?.trim().toLowerCase()
    if (error || !data.user || !identity || !email || !data.user.email_confirmed_at) return errorRedirect(context.mode, 'verification')

    const admin = createAdminClient()
    const linkedAppUserId = await findAppAccountBySupabaseUserId(data.user.id)
    let user: EnvUser
    let created = false
    const linkedSelf = linkedAppUserId ? await findSelfAccountById(linkedAppUserId) : null
    const directEnv = linkedAppUserId ? findEnvUserById(linkedAppUserId) : listEnvUsers().find((item) => item.email.toLowerCase() === email)
    const { data: profiles } = linkedAppUserId || directEnv ? { data: null } : await admin.from('profiles').select('id').ilike('email', emailPattern(email)).limit(1)
    const env = directEnv ?? (!linkedAppUserId && profiles?.[0] ? findEnvUserById(profiles[0].id) : null)
    if (linkedAppUserId && !linkedSelf && !env) return errorRedirect('login', 'account')
    if (env) {
      const override = await getAccountOverride(env.id)
      const role = effectiveRole(env, override)
      if (role === 'admin' || env.role === 'admin') return errorRedirect('login', 'admin')
      user = { ...effectiveIdentity(env, override), role, internal: false }
    } else {
      const existing = linkedSelf ?? await findSelfAccountByEmail(email)
      if (!existing && context.mode === 'login') return errorRedirect('signup', 'no_account')
      if (existing?.blocked_at) return errorRedirect('login', 'blocked')
      if (existing?.role === 'admin') return errorRedirect('login', 'admin')
      if (existing) {
        user = selfAccountAsEnvUser(existing)
      } else {
        const name = String(data.user.user_metadata?.full_name || data.user.user_metadata?.name || email.split('@')[0])
        const result = await ensureSelfAccount({ email, name, role: context.role })
        if (!result.ok || result.account.blocked_at) return errorRedirect(context.mode, 'account')
        created = result.created
        user = selfAccountAsEnvUser(result.account)
      }
      const { data: profile } = await admin.from('profiles').select('company_name').eq('id', user.id).maybeSingle()
      user.company = created ? context.company || null : profile?.company_name ?? null
    }

    if (!(await linkAppAccountToSupabaseUser({ appUserId: user.id, username: user.username, supabaseUserId: data.user.id }))) {
      return errorRedirect('login', 'linked')
    }

    const ip = clientIp(req.headers)
    const userAgent = req.headers.get('user-agent')
    if (await mfaEnabledFor(user.id)) {
      await setMfaPendingCookie({ sub: user.id, username: user.username, next: context.next ?? '/dashboard', auth_method: 'google' })
      await logSecurityEvent({ event: 'login_mfa_required', username: user.username, userId: user.id, ip, userAgent, detail: { via: 'google' } })
      return sameSiteRedirect('/login/mfa')
    }
    await establishSession(user, false, user.id, 'google')
    await logSecurityEvent({ event: 'login_success', username: email, userId: user.id, ip, userAgent, detail: { via: 'google', created, role: user.role, supabase_user_id: data.user.id } })
    return sameSiteRedirect(context.next ?? '/dashboard')
  } catch {
    return errorRedirect(context.mode, 'unavailable')
  }
}
