import 'server-only'

import { createAdminClient } from '@/lib/supabase/admin'
import { identifierToUserId, type EnvUser } from '@/lib/auth/env-users'
import { emailPattern } from '@/lib/like'
import { claimHistoricalProfile, type ClaimResult } from '@/lib/data/historical-profiles'
import type { UserRole } from '@/types/db'

/**
 * Self-service accounts (2026-09-22): a verified email is an account. The
 * row lives in auth_accounts with source = 'self_signup' (no env entry, no
 * password — sign-in is by one-time code). The id is derived from the email
 * the same way env logins derive theirs from the username, so profiles,
 * trips and participants keep working unchanged.
 */
const missing = (e: { message?: string } | null | undefined) => !!e && /does not exist|schema cache|column/i.test(e.message ?? '')

export interface SelfAccount { id: string; email: string; name: string; phone: string | null; role: UserRole; email_verified_at: string | null; blocked_at: string | null; intake_trust_level: number | null; created_at: string }

export function selfAccountId(email: string): string {
  return identifierToUserId(`email:${email.trim().toLowerCase()}`)
}

/** An env login that carries this email wins over a self-service row (the admin provisioned it). */
export async function findSelfAccountByEmail(email: string): Promise<SelfAccount | null> {
  const { data, error } = await createAdminClient().from('auth_accounts').select('user_id, email, name, phone, role, email_verified_at, blocked_at, intake_trust_level, created_at').eq('source', 'self_signup').ilike('email', emailPattern(email.trim().toLowerCase())).maybeSingle()
  if (error || !data) return null
  return { id: data.user_id, email: data.email, name: data.name ?? '', phone: data.phone ?? null, role: (data.role ?? 'dispatcher') as UserRole, email_verified_at: data.email_verified_at, blocked_at: data.blocked_at, intake_trust_level: data.intake_trust_level, created_at: data.created_at }
}

export async function findSelfAccountById(id: string): Promise<SelfAccount | null> {
  const { data, error } = await createAdminClient().from('auth_accounts').select('user_id, email, name, phone, role, email_verified_at, blocked_at, intake_trust_level, created_at').eq('user_id', id).eq('source', 'self_signup').maybeSingle()
  if (error || !data) return null
  return { id: data.user_id, email: data.email, name: data.name ?? '', phone: data.phone ?? null, role: (data.role ?? 'dispatcher') as UserRole, email_verified_at: data.email_verified_at, blocked_at: data.blocked_at, intake_trust_level: data.intake_trust_level, created_at: data.created_at }
}

/** Create or refresh the account after the email code was verified. */
export async function ensureSelfAccount(params: { email: string; name?: string | null; phone?: string | null; role?: UserRole }): Promise<{ ok: true; account: SelfAccount; created: boolean; historical: ClaimResult } | { ok: false; error: string }> {
  const admin = createAdminClient()
  const email = params.email.trim().toLowerCase()
  const existing = await findSelfAccountByEmail(email)
  const now = new Date().toISOString()
  const id = existing?.id ?? selfAccountId(email)
  const name = (params.name?.trim() || existing?.name || email.split('@')[0]).slice(0, 120)
  const { error } = await admin.from('auth_accounts').upsert(
    { user_id: id, username: email, email, name, phone: params.phone?.trim() || existing?.phone || null, role: existing?.role ?? params.role ?? 'dispatcher', source: 'self_signup', email_verified_at: existing?.email_verified_at ?? now, updated_by: 'email verification', updated_at: now },
    { onConflict: 'user_id' },
  )
  if (error) return { ok: false, error: missing(error) ? 'Self-service accounts need database migration 0029.' : error.message }
  await admin.from('profiles').upsert({ id, email, full_name: name, phone: params.phone?.trim() || existing?.phone || null, default_role: existing?.role ?? params.role ?? 'dispatcher' }, { onConflict: 'id' })
  const account = (await findSelfAccountById(id))!
  // The code proved the address: connect any imported historical identity behind it (2026-09-25).
  const historical = await claimHistoricalProfile({ userId: id, email, emailVerified: !!account.email_verified_at, actorLabel: name || email })
  return { ok: true, account, created: !existing, historical }
}

/** Shape a self-service account like an env login so the session code needs no second path. */
export function selfAccountAsEnvUser(a: SelfAccount): EnvUser {
  return { id: a.id, username: a.email, email: a.email, name: a.name || a.email, role: a.role, company: null, phone: a.phone, internal: false }
}
