import 'server-only'

import { createAdminClient } from '@/lib/supabase/admin'
import { isMissingColumn } from '@/lib/db-compat'
import { loadVisibleChat } from '@/lib/data/chat'
import type { ChatMessage, TripParticipant, TripRole, TripUnit } from '@/types/db'
import type { PermitLite, RouteRequestLite } from '@/lib/data/dashboard-data'

/**
 * The extra data the driver experience needs on top of trips + permits:
 * route requests (in all three delivery formats), the per-trip unit profile,
 * and signed permit-file links.
 *
 * Shared by the driver dashboard (`/dashboard?view=driver`) and the driver
 * trip workspace (`/trips/[id]` for a driver) so the two surfaces can never
 * drift apart.
 */

const ROUTE_COLUMNS =
  'id, trip_id, type, state_code, status, route_type, route_links, requested_by, requester_label'
/** Migration 0010 added the GPX and Hummer GPS deliverables. */
const ROUTE_COLUMNS_WITH_FORMATS = `${ROUTE_COLUMNS}, route_gpx_url, route_hummer_url`
/** Migration 0011 added the expired-permit re-order link (Task 75). */
const ROUTE_COLUMNS_ALL = `${ROUTE_COLUMNS_WITH_FORMATS}, replaces_permit_id`

/**
 * Every service request on the driver's trips — routes (all three delivered
 * formats) AND permit requests, so an expired state can show "New permit
 * requested by …" (Task 75). Consumers filter by `type`.
 *
 * Degrades one column set at a time as migrations 0011 → 0010 are missing.
 */
export async function loadDriverRouteRequests(tripIds: string[]): Promise<RouteRequestLite[]> {
  if (tripIds.length === 0) return []
  const admin = createAdminClient()

  const query = (columns: string) =>
    admin
      .from('service_requests')
      .select(columns)
      .in('trip_id', tripIds)
      .in('type', ['route_request', 'permit_request'])

  let res = await query(ROUTE_COLUMNS_ALL)
  if (isMissingColumn(res.error, 'replaces_permit_id')) res = await query(ROUTE_COLUMNS_WITH_FORMATS)
  if (isMissingColumn(res.error, 'route_gpx_url', 'route_hummer_url')) res = await query(ROUTE_COLUMNS)

  const rows = (res.data ?? []) as unknown as Partial<RouteRequestLite>[]
  const withDefaults = rows.map((r) => ({
    ...r,
    route_gpx_url: r.route_gpx_url ?? null,
    route_hummer_url: r.route_hummer_url ?? null,
    replaces_permit_id: r.replaces_permit_id ?? null,
  })) as RouteRequestLite[]
  return signRouteFormats(withDefaults)
}

/**
 * A GPX file lives in the private `trip-documents` bucket (a storage path,
 * not a URL) so it never expires in the database; sign it at read time. A
 * real http(s) link is passed through untouched.
 */
export async function signRouteFormats<T extends { route_gpx_url: string | null }>(rows: T[]): Promise<T[]> {
  const paths = [...new Set(rows.map((r) => r.route_gpx_url).filter((u): u is string => !!u && !/^https?:\/\//i.test(u)))]
  if (paths.length === 0) return rows
  const admin = createAdminClient()
  const signed = new Map<string, string>()
  await Promise.all(
    paths.map(async (path) => {
      const { data } = await admin.storage.from('trip-documents').createSignedUrl(path, 60 * 30)
      if (data?.signedUrl) signed.set(path, data.signedUrl)
    }),
  )
  return rows.map((r) =>
    r.route_gpx_url && signed.has(r.route_gpx_url) ? { ...r, route_gpx_url: signed.get(r.route_gpx_url)! } : r,
  )
}

/** Tolerates a missing trip_units table (migration 0006 not applied yet). */
export async function loadDriverUnits(tripIds: string[]): Promise<TripUnit[]> {
  if (tripIds.length === 0) return []
  const admin = createAdminClient()
  const { data } = await admin.from('trip_units').select('*').in('trip_id', tripIds)
  return (data ?? []) as TripUnit[]
}

/** Short-lived signed URLs for the permit PDFs the driver can open. */
export async function signPermitUrls(permits: PermitLite[]): Promise<Record<string, string>> {
  const urls: Record<string, string> = {}
  const docIds = [...new Set(permits.map((p) => p.document_id).filter(Boolean))] as string[]
  if (docIds.length === 0) return urls

  const admin = createAdminClient()
  const { data: permitDocs } = await admin
    .from('documents')
    .select('id, storage_path')
    .in('id', docIds)

  await Promise.all(
    (permitDocs ?? []).map(async (d) => {
      const { data } = await admin.storage
        .from('trip-documents')
        .createSignedUrl(d.storage_path, 60 * 30)
      if (data?.signedUrl) urls[d.id] = data.signedUrl
    }),
  )
  return urls
}

export type DriverTripData = {
  routeRequests: RouteRequestLite[]
  units: TripUnit[]
  permitUrls: Record<string, string>
}

/** Everything at once — used by the driver dashboard. */
export async function loadDriverTripData(
  tripIds: string[],
  permits: PermitLite[],
): Promise<DriverTripData> {
  if (tripIds.length === 0) return { routeRequests: [], units: [], permitUrls: {} }
  const [routeRequests, units, permitUrls] = await Promise.all([
    loadDriverRouteRequests(tripIds),
    loadDriverUnits(tripIds),
    signPermitUrls(permits),
  ])
  return { routeRequests, units, permitUrls }
}

/**
 * The focused trip's conversation and people, for the driver's inline Agent
 * pane on the dashboard (the trip page already has both loaded).
 */
export async function loadDriverChat(
  tripId: string | null,
  user: { id: string; email: string },
): Promise<{
  chat: ChatMessage[]
  participants: TripParticipant[]
  myRole: TripRole | null
  shareChat: boolean
}> {
  if (!tripId) return { chat: [], participants: [], myRole: null, shareChat: true }
  const admin = createAdminClient()
  const [chat, participantsRes] = await Promise.all([
    // Privacy-filtered: another participant's private questions never reach
    // this payload (2026-09-07).
    loadVisibleChat(tripId, user.id),
    admin
      .from('trip_participants')
      .select('*')
      .eq('trip_id', tripId)
      .neq('status', 'removed')
      .order('created_at'),
  ])
  const participants = (participantsRes.data ?? []) as TripParticipant[]
  // Same resolution order as getMyParticipant: user id first, then email.
  const me =
    participants.find((p) => p.user_id === user.id) ??
    participants.find((p) => p.email.toLowerCase() === user.email.toLowerCase()) ??
    null
  return {
    chat: chat.messages,
    participants,
    myRole: me?.role ?? null,
    shareChat: me?.share_chat !== false,
  }
}

/**
 * Pilot access per pilot participant on one trip, for the driver's state
 * cards (Nash, 2026-09-12: "if he has a pilot attached to that trip… show him
 * the information about the pilot… and for what states they are hired").
 * Read from trip history; tolerant of an unreachable table.
 */
export async function loadPilotAccess(tripId: string | null): Promise<Record<string, string>> {
  if (!tripId) return {}
  const admin = createAdminClient()
  const { data } = await admin
    .from('trip_events')
    .select('action, detail')
    .eq('trip_id', tripId)
    .eq('action', 'participant_invited')
    .order('created_at')
  const { pilotAccessFromEvents } = await import('@/lib/domain/pilot')
  return pilotAccessFromEvents((data ?? []) as { action: string; detail: Record<string, unknown> | null }[])
}
