import type { TripRole } from '@/types/db'

/**
 * Which carrier is performing a trip (Nash, 2026-09-19).
 *
 * "The carrier name, MC, and DOT number — those are the three things every
 * broker needs to see when he goes to Overview… once he invites a
 * dispatcher, that dispatcher will have a relation with the carrier, and
 * that carrier information should be displayed. If the dispatcher has only
 * one relation, by default we pull that relation and display it. If the
 * dispatcher has relations with four different carriers, we're not going to
 * show the carrier until the dispatch selects which carrier will be attached
 * to this order."
 *
 * A "relation" is an approved company membership on a carrier company — the
 * same record the company verification flow already keeps. The assignment
 * lives in trips.carrier_company_id. Trips imported from Synchron arrive
 * with it set, so they resolve as `assigned` from the first render.
 *
 * Pure: the loader gathers the rows, this decides.
 */
export interface CarrierSummary {
  id: string
  name: string
  mc: string | null
  dot: string | null
}

export type CarrierResolution =
  /** trips.carrier_company_id is set — show it. */
  | { kind: 'assigned'; carrier: CarrierSummary }
  /** Not set, but the trip's dispatcher(s) relate to exactly one carrier — attach it by default. */
  | { kind: 'auto'; carrier: CarrierSummary }
  /** Not set and the dispatcher(s) relate to several — the dispatcher must choose. */
  | { kind: 'choose'; options: CarrierSummary[] }
  /** Nothing to resolve from: no dispatcher with an account, or none with a carrier relation. */
  | { kind: 'none'; reason: 'no_dispatcher' | 'no_relations' }

export function resolveCarrier(params: {
  assigned: CarrierSummary | null
  /** True when at least one dispatcher participant has an account (user_id). */
  hasDispatcherAccount: boolean
  /** Carrier relations across the trip's dispatcher accounts, de-duplicated. */
  dispatcherCarriers: CarrierSummary[]
  /** The free-text carrier the trip was created with, if any. */
  tripCarrierName?: string | null
}): CarrierResolution {
  if (params.assigned) return { kind: 'assigned', carrier: params.assigned }
  if (!params.hasDispatcherAccount) return { kind: 'none', reason: 'no_dispatcher' }
  const seen = new Map<string, CarrierSummary>()
  for (const c of params.dispatcherCarriers) if (!seen.has(c.id)) seen.set(c.id, c)
  const options = [...seen.values()].sort((a, b) => a.name.localeCompare(b.name))
  if (options.length === 0) return { kind: 'none', reason: 'no_relations' }
  if (options.length === 1) {
    // One relation attaches by default — unless the trip was created naming a
    // different carrier, in which case the dispatcher confirms rather than
    // having that text silently replaced.
    const typed = params.tripCarrierName?.trim()
    if (typed && !sameCarrierName(typed, options[0].name)) return { kind: 'choose', options }
    return { kind: 'auto', carrier: options[0] }
  }
  return { kind: 'choose', options }
}

/** "PAN LOGISTICS INC" ≈ "Pan Logistics, Inc." — punctuation and case do not make a different carrier. */
export function sameCarrierName(a: string, b: string): boolean {
  const norm = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, '')
  return norm(a) === norm(b)
}

/**
 * Who may pick the carrier when there are several: the dispatcher ("the
 * dispatch needs to choose which carrier will be performing this trip") and
 * an admin (every tool, every trip).
 */
export function canAssignCarrier(params: { viewerRole: TripRole | null; viewerIsAdmin: boolean }): boolean {
  return params.viewerIsAdmin || params.viewerRole === 'dispatcher'
}

/** "MC 1130384 · DOT 3462028", or what is known, or nothing. */
export function carrierIdLine(c: Pick<CarrierSummary, 'mc' | 'dot'>): string {
  return [c.mc ? `MC ${c.mc}` : null, c.dot ? `DOT ${c.dot}` : null].filter(Boolean).join(' · ')
}
