import { describe, expect, it } from 'vitest'
import {
  canManagePilotAccess,
  describePilotAccess,
  parsePilotAccessLine,
  PILOT_ACCESS_SHARED_ACTION,
  pilotAccessFromEvents,
  shareableWithin,
  type PilotInviteAccess,
} from '@/lib/domain/pilot'

/**
 * Sharing permits with a pilot after the invitation (Nash, 2026-09-17).
 *
 * "It has a relation to the person they invited that pilot. So if a broker
 * invited the pilot, he's the one that has the power to share permits. If the
 * dispatcher invited the pilot, he's the one… if a truck driver invited the
 * pilot, he is the one… an admin has overall power to do the same thing for
 * any pilot car."
 *
 * And, for a pilot dispatch re-sharing downstream: "a pilot dispatch [given]
 * two or three permits… has the power to assign out of those two or three
 * permits any other ones to any of the drivers."
 */

const DISPATCHER = 'user-dispatcher'
const BROKER = 'user-broker'
const DRIVER = 'user-truck-driver'

const PERMITS = [
  { id: 'p-oh', state_code: 'OH', permit_number: '111' },
  { id: 'p-pa', state_code: 'PA', permit_number: '222' },
  { id: 'p-tx', state_code: 'TX', permit_number: '333' },
]

describe('who may share permits with a pilot', () => {
  it('the person who invited that pilot can — whatever their role', () => {
    for (const inviter of [DISPATCHER, BROKER, DRIVER]) {
      expect(canManagePilotAccess({ pilotInvitedBy: inviter, viewerUserId: inviter, viewerIsAdmin: false })).toBe(true)
    }
  })

  it('someone else on the trip cannot, even another dispatcher', () => {
    expect(canManagePilotAccess({ pilotInvitedBy: DISPATCHER, viewerUserId: BROKER, viewerIsAdmin: false })).toBe(false)
    expect(canManagePilotAccess({ pilotInvitedBy: DISPATCHER, viewerUserId: 'user-other-dispatcher', viewerIsAdmin: false })).toBe(false)
  })

  it('an admin can, for any pilot car, including one they did not invite', () => {
    expect(canManagePilotAccess({ pilotInvitedBy: DISPATCHER, viewerUserId: 'user-admin', viewerIsAdmin: true })).toBe(true)
    // …and even when nobody is recorded as the inviter.
    expect(canManagePilotAccess({ pilotInvitedBy: null, viewerUserId: 'user-admin', viewerIsAdmin: true })).toBe(true)
  })

  it('an unknown inviter grants nobody the power (except admin)', () => {
    expect(canManagePilotAccess({ pilotInvitedBy: null, viewerUserId: DISPATCHER, viewerIsAdmin: false })).toBe(false)
    expect(canManagePilotAccess({ pilotInvitedBy: DISPATCHER, viewerUserId: null, viewerIsAdmin: false })).toBe(false)
  })
})

describe('a pilot can never hand out more than they hold', () => {
  it('a pilot dispatch given two permits may only offer those two', () => {
    const held: PilotInviteAccess = { type: 'permits', permit_ids: ['p-oh', 'p-pa'] }
    const bound = shareableWithin(held, PERMITS)
    expect(bound.permits.map((p) => p.id)).toEqual(['p-oh', 'p-pa'])
    expect(bound.states).toEqual(['OH', 'PA'])
    expect(bound.fullTrip).toBe(false)
  })

  it('a pilot dispatch given two states may offer every permit in those states', () => {
    const bound = shareableWithin({ type: 'states', states: ['OH', 'TX'] }, PERMITS)
    expect(bound.permits.map((p) => p.id)).toEqual(['p-oh', 'p-tx'])
  })

  it('a pilot holding nothing yet can offer nothing', () => {
    expect(shareableWithin({ type: 'decide_later' }, PERMITS)).toEqual({ permits: [], states: [], fullTrip: false })
  })

  it('the carrier side — no holder — may offer the whole trip', () => {
    expect(shareableWithin(null, PERMITS).permits).toHaveLength(3)
    expect(shareableWithin(null, PERMITS).fullTrip).toBe(true)
    expect(shareableWithin({ type: 'full_trip' }, PERMITS).fullTrip).toBe(true)
  })
})

describe('a later share replaces what the invitation set', () => {
  it('reads the newest access event per pilot', () => {
    const events = [
      { action: 'participant_invited', detail: { email: 'Pilot@Example.com', pilot_access: 'Decide later' } },
      { action: PILOT_ACCESS_SHARED_ACTION, detail: { email: 'pilot@example.com', pilot_access: 'States: OH, PA' } },
    ]
    expect(pilotAccessFromEvents(events)).toEqual({ 'pilot@example.com': 'States: OH, PA' })
  })

  it('a second share replaces the first', () => {
    const events = [
      { action: PILOT_ACCESS_SHARED_ACTION, detail: { email: 'p@e.com', pilot_access: 'States: OH' } },
      { action: PILOT_ACCESS_SHARED_ACTION, detail: { email: 'p@e.com', pilot_access: 'Full trip (all states)' } },
    ]
    expect(pilotAccessFromEvents(events)['p@e.com']).toBe('Full trip (all states)')
  })

  it('ignores events that carry no access, and other people', () => {
    const events = [
      { action: 'document_uploaded', detail: { email: 'p@e.com', pilot_access: 'Full trip (all states)' } },
      { action: PILOT_ACCESS_SHARED_ACTION, detail: { email: 'other@e.com', pilot_access: 'States: TX' } },
    ]
    expect(pilotAccessFromEvents(events)).toEqual({ 'other@e.com': 'States: TX' })
  })
})

describe('the chooser opens on what the pilot already holds', () => {
  it('round-trips every access shape', () => {
    const cases: PilotInviteAccess[] = [
      { type: 'full_trip' },
      { type: 'states', states: ['OH', 'PA'] },
      { type: 'permits', permit_ids: ['p-oh', 'p-tx'], labels: ['OH · 111', 'TX · 333'] },
      { type: 'decide_later' },
    ]
    for (const access of cases) {
      const parsed = parsePilotAccessLine(describePilotAccess(access), PERMITS)
      expect(parsed.type).toBe(access.type)
      if (access.type === 'states' && parsed.type === 'states') expect(parsed.states).toEqual(access.states)
      if (access.type === 'permits' && parsed.type === 'permits') expect(parsed.permit_ids).toEqual(access.permit_ids)
    }
  })

  it('falls back to sharing nothing when the line cannot be read', () => {
    expect(parsePilotAccessLine('Decide later', PERMITS)).toEqual({ type: 'decide_later' })
    expect(parsePilotAccessLine(null, PERMITS)).toEqual({ type: 'decide_later' })
    // A permit that is no longer on the trip must not resurrect as access.
    expect(parsePilotAccessLine('Permits: ZZ · 999', PERMITS)).toEqual({ type: 'decide_later' })
  })
})
