import 'server-only'
import { createAdminClient } from '@/lib/supabase/admin'
import { ensureBrokerPage } from '@/lib/auth/establish-session'
import { getVisibleTrips, getTripCompletions } from '@/lib/data/trips'
import { loadDriverTripData, loadDriverChat, loadPilotAccess } from '@/lib/data/driver'
import { getRouteCreditBalance } from '@/lib/data/credits'
import { listContacts } from '@/lib/data/contacts'
import { getCompanyContext } from '@/lib/data/companies'
import { companyRoleLabel } from '@/lib/domain/company'
import { isActiveStatus, resolveStatusForUser, type TripCompletion } from '@/lib/domain/status'
import type { SessionUser } from '@/lib/auth'
import { contextForAccount } from '@/lib/page-context'
import type { BrokerPage, Trip, TripWarning } from '@/types/db'
import { inChunks } from '@/lib/data/chunked'
import { pilotAccessFromEvents, pilotStatesFromAccess } from '@/lib/domain/pilot'
import type { PermitLite, TripDriver, TripPilot } from '@/lib/data/dashboard-data'

/**
 * Dashboard data loaders, one per role page (article "Role-Specific Page
 * Separation", 2026-09-13). Extracted unchanged from the former single
 * /dashboard route so each role route loads only what its dashboard uses.
 */

export interface DashboardBase {
  trips: Trip[]
  warnings: TripWarning[]
  permits: PermitLite[]
  drivers: TripDriver[]
  /** Pilot cars per trip with the states each is assigned (2026-09-17). */
  pilots: TripPilot[]
  completions: Record<string, TripCompletion>
}

/** Trips, warnings, per-trip permits and drivers, personal completion — used by every role dashboard. */
export async function loadDashboardBase(user: SessionUser): Promise<DashboardBase> {
  const admin = createAdminClient()
  const { trips, warnings } = await getVisibleTrips(user)
  const ids = trips.map((t) => t.id)
  let permits: PermitLite[] = []
  let drivers: TripDriver[] = []
  let pilots: TripPilot[] = []
  if (ids.length > 0) {
    const [permitsRes, driversRes] = await Promise.all([
      admin
        .from('permits')
        .select('id, trip_id, document_id, state_code, permit_number, effective_date, expiration_date, route_processing_status, route_links, route_gpx_url, route_hummer_url, source_system')
        .in('trip_id', ids)
        .order('created_at'),
      admin
        .from('trip_participants')
        .select('trip_id, name, email')
        .in('trip_id', ids)
        .eq('role', 'driver')
        .neq('status', 'removed'),
    ])
    permits = (permitsRes.data ?? []) as PermitLite[]
    drivers = (driversRes.data ?? []) as TripDriver[]
    pilots = await loadTripPilots(ids, permits)
  }
  // Personal completion state — every dashboard renders the status THIS user
  // sees, not a single trip-wide one (2026-09-07).
  const completions = await getTripCompletions(user, ids)
  return { trips, warnings, permits, drivers, pilots, completions }
}

/**
 * Every pilot car on these trips and the states each is assigned (Nash,
 * 2026-09-17: the dashboards' pilot badge "needs to be dynamic… if it's two
 * different pilot cars and one is assigned for certain states, another one
 * for another, it should visually represent that").
 *
 * Access is read from the trip history the same way the trip workspace and
 * the driver's state cards read it — the invitation or a later "Share
 * permits", latest wins — so all three surfaces always agree. Chunked: an
 * admin passes every trip on the platform.
 */
async function loadTripPilots(tripIds: string[], permits: PermitLite[]): Promise<TripPilot[]> {
  const admin = createAdminClient()
  type PilotRow = { id: string; trip_id: string; name: string; email: string; invited_by: string | null }
  type EventRow = { trip_id: string; action: string; detail: Record<string, unknown> | null }
  const [pilotRows, eventRows] = await Promise.all([
    inChunks<PilotRow>(tripIds, (chunk) =>
      admin.from('trip_participants').select('id, trip_id, name, email, invited_by').in('trip_id', chunk).eq('role', 'pilot').neq('status', 'removed'),
    ),
    inChunks<EventRow>(tripIds, (chunk) =>
      admin
        .from('trip_events')
        .select('trip_id, action, detail')
        .in('trip_id', chunk)
        .in('action', ['participant_invited', 'pilot_access_shared', 'participant_auto_added'])
        .order('created_at'),
    ),
  ])
  if (pilotRows.data.length === 0) return []

  const eventsByTrip = new Map<string, EventRow[]>()
  for (const e of eventRows.data) {
    const list = eventsByTrip.get(e.trip_id)
    if (list) list.push(e)
    else eventsByTrip.set(e.trip_id, [e])
  }
  const statesByTrip = new Map<string, string[]>()
  for (const p of permits) {
    if (!p.state_code) continue
    const list = statesByTrip.get(p.trip_id)
    if (list) {
      if (!list.includes(p.state_code)) list.push(p.state_code)
    } else statesByTrip.set(p.trip_id, [p.state_code])
  }

  return pilotRows.data.map((p) => {
    const access = pilotAccessFromEvents(eventsByTrip.get(p.trip_id) ?? [])[p.email.toLowerCase()] ?? 'Decide later'
    return {
      trip_id: p.trip_id,
      participant_id: p.id,
      name: p.name || p.email,
      email: p.email,
      invited_by: p.invited_by,
      access,
      states: pilotStatesFromAccess(access, statesByTrip.get(p.trip_id) ?? []),
    }
  })
}

/**
 * Self-heal: brokers always have an intake page. Decided by PAGE CONTEXT, not
 * the raw account role — an admin lands on the freight broker pages and needs
 * the same intake page for "New Trip Request" (regression 2026-09-13: the
 * admin account fell through to the generic form).
 */
export async function loadBrokerPage(user: SessionUser): Promise<BrokerPage | null> {
  // Internal testers may reach the freight broker pages while their session is
  // another test account (the pilot testing bar's Broker button is a link,
  // not a session switch, since no broker test login exists). They still get
  // an intake page, so Copy Intake Link and New Trip Request keep working
  // (regression 2026-09-13).
  if (contextForAccount(user.role) !== 'broker' && !user.internal) return null
  const admin = createAdminClient()
  const { data } = await admin.from('broker_pages').select('*').eq('owner_id', user.id).maybeSingle()
  if (data) return data as BrokerPage
  await ensureBrokerPage(user.id, user.company || user.name)
  const { data: created } = await admin.from('broker_pages').select('*').eq('owner_id', user.id).maybeSingle()
  return (created as BrokerPage | null) ?? null
}

export type CompanyStatus = { label: string; href: string; tone: 'ok' | 'pending' | 'none' } | null

/** Company verification chip (Task 89) — broker and carrier accounts only. */
export async function loadCompanyStatus(user: SessionUser): Promise<CompanyStatus> {
  if (user.role !== 'broker' && user.role !== 'dispatcher') return null
  const ctx = await getCompanyContext(user.id)
  if (!ctx.available) return null
  // Carrier Dashboard has its own Company Info tab (2026-09-19); brokers keep /company and /settings.
  const carrier = user.role === 'dispatcher'
  const infoHref = carrier ? '/cd-dashboard?tab=company-info' : '/fb-dashboard?tab=company-info'
  if (ctx.membership?.status === 'approved' && ctx.company) {
    return {
      label: carrier
        ? `Verified dispatcher · ${ctx.company.display_name}`
        : `Approved company agent · ${ctx.company.display_name} · ${companyRoleLabel(ctx.membership.role, ctx.company.company_type)}`,
      href: infoHref,
      tone: 'ok',
    }
  }
  if (ctx.membership?.status === 'pending' || (ctx.claim && ['pending_corporate_approval', 'company_verification_pending', 'admin_review_required'].includes(ctx.claim.claim_status))) {
    return { label: carrier ? 'Carrier relationship: waiting for verification' : 'Broker company: waiting for verification', href: infoHref, tone: 'pending' }
  }
  return { label: carrier ? 'Carrier: not connected · Company Info' : 'Broker company: not connected · Company Info', href: infoHref, tone: 'none' }
}

/** Saved drivers and brokers for the carrier dashboard's Drivers tab (Task 98). */
export async function loadCarrierContacts(user: SessionUser) {
  return listContacts(user.id)
}

/**
 * Carrier driver dashboard extras: permit file links, route requests in all
 * three delivery formats, unit profiles, the focused trip's chat, credits,
 * and each pilot's access for the state cards.
 */
export async function loadDriverDashboard(user: SessionUser, base: DashboardBase) {
  const ids = base.trips.map((t) => t.id)
  const { routeRequests, units, permitUrls } = await loadDriverTripData(ids, base.permits)
  // Must match the driver view's own focus rule exactly — its first active
  // trip, judged by the status THIS user sees.
  const focusedTripId =
    base.trips.find((t) => isActiveStatus(resolveStatusForUser(t.status, base.completions[t.id])))?.id ?? null
  const [routeCredits, chatBundle, pilotAccess] = await Promise.all([
    getRouteCreditBalance(user),
    loadDriverChat(focusedTripId, user),
    loadPilotAccess(focusedTripId),
  ])
  return { routeRequests, units, permitUrls, routeCredits, ...chatBundle, pilotAccess }
}
