import 'server-only'

import { redirect } from 'next/navigation'
import { readSession } from '@/lib/auth/session'
import { effectiveRole, getAccountOverride, isSessionRevoked } from '@/lib/auth/accounts'
import { findEnvUserById } from '@/lib/auth/env-users'
import { isInternalRole } from '@/lib/domain/roles'
import { createAdminClient } from '@/lib/supabase/admin'
import type { Profile, TripParticipant, UserRole } from '@/types/db'

/** Signed-in user resolved from the .env-auth session cookie. */
export interface SessionUser {
  id: string
  email: string
  name: string
  role: UserRole
  company: string | null
  /** Signed in as an admin — gates pilot/preview tooling. */
  internal: boolean
  /** The account that actually signed in (differs during a pilot role switch). */
  originId: string
}

export async function getSessionUser(): Promise<SessionUser | null> {
  const session = await readSession()
  if (!session) return null
  // A password reset or role change made by an admin ends every session
  // issued before it (2026-09-11) — otherwise a reset would not lock out an
  // old session, and a demoted admin would keep admin for up to 7 days.
  if (await isSessionRevoked(session.iat, [session.sub, session.origin_sub])) return null
  const originId = session.origin_sub ?? session.sub

  // The role and the admin tooling are resolved LIVE from AUTH_USERS plus the
  // admin overrides, not from what the cookie froze at sign-in. A cookie
  // lasts 7 days; when Nash_Turcan was promoted to admin in the env, the old
  // cookie kept saying "broker" and hid the users / moderation / templates /
  // company-review pages and the pilot bar until a manual sign-out. An
  // account removed from AUTH_USERS loses its session at once.
  const env = findEnvUserById(session.sub)
  if (!env) return null
  const role = effectiveRole(env, await getAccountOverride(env.id))

  // Admin powers follow whoever actually SIGNED IN: an admin who switched
  // into the driver test account keeps the pilot bar that switches them back.
  let internal = isInternalRole(role)
  if (!internal && originId !== session.sub) {
    const originEnv = findEnvUserById(originId)
    internal = !!originEnv && isInternalRole(effectiveRole(originEnv, await getAccountOverride(originEnv.id)))
  }

  return {
    id: session.sub,
    email: session.email,
    name: session.name,
    role,
    company: session.company ?? null,
    internal,
    originId,
  }
}

export async function requireUser(): Promise<SessionUser> {
  const user = await getSessionUser()
  if (!user) redirect('/login')
  return user
}

export async function getProfile(): Promise<Profile | null> {
  const user = await getSessionUser()
  if (!user) return null
  const admin = createAdminClient()
  const { data } = await admin.from('profiles').select('*').eq('id', user.id).maybeSingle()
  if (data) return data as Profile
  // Fall back to the session itself (profile rows are upserted at sign-in).
  return {
    id: user.id,
    email: user.email,
    full_name: user.name,
    phone: null,
    company_name: user.company,
    default_role: user.role,
    created_at: new Date().toISOString(),
  }
}

/** The caller's participant row on a trip (matches by user id or email). */
export async function getMyParticipant(tripId: string): Promise<TripParticipant | null> {
  const user = await getSessionUser()
  if (!user) return null
  const admin = createAdminClient()
  const { data } = await admin
    .from('trip_participants')
    .select('*')
    .eq('trip_id', tripId)
    .neq('status', 'removed')
  const rows = (data ?? []) as TripParticipant[]
  return (
    rows.find((p) => p.user_id === user.id) ??
    rows.find((p) => p.email.toLowerCase() === user.email.toLowerCase()) ??
    null
  )
}
