/**
 * Pilot car invoicing & expense tracking — domain rules (Phase 1 replica).
 *
 * Source: "HeavyHaul Agent Pro Tools, Pilot Car Invoicing, Expense Tracking,
 * and Plan Strategy" (article, 2026-09-12) + Nash's answers the same day.
 * Pure data and pure functions — no I/O — so the later backend reuses them.
 */

import type { PilotAccountType } from '@/lib/domain/pilot'

/* ------------------------------ Plans ------------------------------ */

// Nash, 2026-09-13: Fleet ($99) replaced by Pro Plus ($59) — the higher plan above Pro, not a team package.
export type PlanName = 'Free' | 'Starter' | 'Pro' | 'Pro Plus'
export const PLAN_NAMES_FOR_PREVIEW: PlanName[] = ['Free', 'Starter', 'Pro', 'Pro Plus']

/**
 * Article §20 / §35: "Invoice and expense tools should be available when the
 * owner of the assignment has Pro or Fleet" (Fleet is now Pro Plus). Starter cannot in MVP.
 * Nash: "the plans are the same across any type of users" — one plan
 * vocabulary for everyone.
 */
export function canUseBusinessTools(plan: PlanName): boolean {
  return plan === 'Pro' || plan === 'Pro Plus'
}

/**
 * Who an expense belongs to. Pilot drivers and pilot companies (article
 * §13) — and, Nash 2026-09-13, carrier truck drivers: "the truck drivers must
 * also have the ability to track their expenses related to the trip."
 * A carrier driver's expenses never go on an invoice (no invoice tool).
 */
export type ExpenseOwnerType = PilotAccountType | 'carrier_driver'

/** Article §24 — the locked state is visible, never hidden. */
export const LOCKED_PRO_COPY = {
  title: 'Create Invoice - Pro Feature',
  subtext:
    'Upgrade to Pro to create trip invoices, calculate mileage vs daily rate, add overnight fees, track expenses, and send professional invoices by email.',
  upgrade: 'Upgrade to Pro',
  notNow: 'Not Now',
} as const

/** Locked expense tracking (pilot drivers and carrier truck drivers alike). */
export const EXPENSES_LOCKED_COPY = {
  title: 'Expense Tracking - Pro Feature',
  subtext: 'Upgrade to Pro to track fuel, tolls, hotel and other trip expenses with receipts and a per-trip summary.',
  upgrade: 'Upgrade to Pro',
  notNow: 'Not Now',
} as const

/* ---------------- Brokers & carriers: pilot paperwork ---------------- */

/**
 * Nash, 2026-09-13 (two voice notes). On a trip, the "My Pilot" tab shows the
 * pilot's paperwork (COI, licenses, certifications — everything, each with a
 * PDF to open) plus a missing-paperwork alert, for **brokers and carriers**
 * (carrier dispatchers and drivers) "to track the paperwork for each pilot
 * assigned to a trip". Second note: "this feature should be part of our
 * Starter package… everyone that signs up will have this feature unlocked
 * for ninety days for free even if they don't have any membership. If they
 * are Starter package or higher, they all get this feature."
 *
 * Invoices are NOT behind the plan: "if the invoice was created and sent to
 * them, they will see it regardless of their plan."
 */
export const PAPERWORK_TRIAL_DAYS = 90

export type PaperworkAccess =
  | { mode: 'included' }
  | { mode: 'trial'; daysLeft: number }
  | { mode: 'locked' }

export function pilotPaperworkAccess(input: { plan: PlanName; signedUpAt: string; today: string }): PaperworkAccess {
  if (input.plan !== 'Free') return { mode: 'included' }
  const ms = new Date(input.today.slice(0, 10)).getTime() - new Date(input.signedUpAt.slice(0, 10)).getTime()
  const daysSince = Math.max(0, Math.floor(ms / 86_400_000))
  const daysLeft = PAPERWORK_TRIAL_DAYS - daysSince
  return daysLeft > 0 ? { mode: 'trial', daysLeft } : { mode: 'locked' }
}

/** Who the feature is for — shown on the tab so users understand its purpose. */
export const PAPERWORK_PURPOSE =
  'Built for brokers, carrier dispatchers and drivers: track the paperwork of every pilot assigned to this trip.'

/** The incentive card for a Free account after the 90 days. */
export const PAPERWORK_LOCKED_COPY = {
  title: 'Pilot paperwork - Starter Feature',
  subtext:
    'Brokers, carrier dispatchers and drivers on Starter and higher see every pilot\'s certificate of insurance, certifications and licenses right here on the trip - with expiration dates - so you know the escort is covered before the load moves.',
  upgrade: 'Upgrade to Starter',
  notNow: 'Not Now',
} as const

/* --------------------------- Ownership ----------------------------- */

/**
 * Article §22: managed by a pilot company → the company owns the invoice;
 * accepted directly by an independent driver → the driver owns it.
 * "Invoice access depends on the owner's subscription."
 */
export function invoiceOwner(input: {
  managedByCompany: boolean
}): PilotAccountType {
  return input.managedByCompany ? 'pilot_company' : 'pilot_driver'
}

/* ------------------------- Calculation (§9) ------------------------- */

export interface InvoiceInputs {
  miles: number
  ratePerMile: number
  days: number
  dailyRate: number
  overnights: number
  overnightFee: number
  /** Expenses marked "include on invoice" (§13). */
  expenseAmounts: number[]
  /** Custom line items (§12): description, amount, notes — amount is what counts. */
  customAmounts: number[]
}

export interface InvoiceCalculation {
  mileageTotal: number
  dailyTotal: number
  selectedBaseType: 'mileage' | 'daily'
  selectedBaseTotal: number
  overnightTotal: number
  expenseTotal: number
  customTotal: number
  invoiceTotal: number
  /** Article §11 example language. */
  explanation: string
}

const round2 = (n: number) => Math.round((n + Number.EPSILON) * 100) / 100

/**
 * "The system should not automatically charge both mileage and daily rate as
 * the base. It should calculate both and select whichever is greater." (§9)
 */
export function calculateInvoice(i: InvoiceInputs): InvoiceCalculation {
  const mileageTotal = round2((i.miles || 0) * (i.ratePerMile || 0))
  const dailyTotal = round2((i.days || 0) * (i.dailyRate || 0))
  const selectedBaseType: 'mileage' | 'daily' = dailyTotal > mileageTotal ? 'daily' : 'mileage'
  const selectedBaseTotal = selectedBaseType === 'daily' ? dailyTotal : mileageTotal
  const overnightTotal = round2((i.overnights || 0) * (i.overnightFee || 0))
  const expenseTotal = round2(i.expenseAmounts.reduce((a, b) => a + (b || 0), 0))
  const customTotal = round2(i.customAmounts.reduce((a, b) => a + (b || 0), 0))
  const invoiceTotal = round2(selectedBaseTotal + overnightTotal + expenseTotal + customTotal)
  const explanation =
    mileageTotal === dailyTotal
      ? 'Mileage and daily totals are equal; the mileage total was used.'
      : selectedBaseType === 'daily'
        ? 'Daily rate was selected because it is greater than the mileage total.'
        : 'Mileage rate was selected because it is greater than the daily total.'
  return {
    mileageTotal,
    dailyTotal,
    selectedBaseType,
    selectedBaseTotal,
    overnightTotal,
    expenseTotal,
    customTotal,
    invoiceTotal,
    explanation,
  }
}

export function money(n: number): string {
  return n.toLocaleString('en-US', { style: 'currency', currency: 'USD' })
}

/* ------------------------ Statuses & options ------------------------ */

/** Article §18 MVP statuses; the type leaves room for the future ones. */
export type InvoiceStatus = 'Draft' | 'Sent' | 'Paid' | 'Cancelled'
export const INVOICE_STATUSES: InvoiceStatus[] = ['Draft', 'Sent', 'Paid', 'Cancelled']

/**
 * Nash, 2026-09-12: "the due date, it should be something optional. He can
 * choose… ASAP, one day, three days, seven days, fourteen days, thirty days,
 * sixty days."
 */
export const DUE_DATE_OPTIONS = [
  { key: 'asap', label: 'ASAP', days: 0 },
  { key: '1', label: '1 day', days: 1 },
  { key: '3', label: '3 days', days: 3 },
  { key: '7', label: '7 days', days: 7 },
  { key: '14', label: '14 days', days: 14 },
  { key: '30', label: '30 days', days: 30 },
  { key: '60', label: '60 days', days: 60 },
] as const
export type DueDateKey = (typeof DUE_DATE_OPTIONS)[number]['key']

export function dueDateFor(invoiceDateIso: string, key: DueDateKey | null): string | null {
  if (!key) return null
  const opt = DUE_DATE_OPTIONS.find((o) => o.key === key)
  if (!opt) return null
  const d = new Date(`${invoiceDateIso}T00:00:00`)
  d.setDate(d.getDate() + opt.days)
  return d.toISOString().slice(0, 10)
}

/**
 * Nash, 2026-09-12: "the invoice maybe should include… pilot and then invoice
 * and then the trip number and then the date… good anchor points."
 * → `PILOT-INV-<trip ref>-<YYYYMMDD>`; a second invoice for the same trip on
 * the same day gets `-2`, `-3`, … so numbers stay unique.
 */
export function nextInvoiceNumber(existingNumbers: string[], tripRef: string, invoiceDateIso: string): string {
  const base = `PILOT-INV-${tripRef}-${invoiceDateIso.replace(/-/g, '')}`
  if (!existingNumbers.includes(base)) return base
  let n = 2
  while (existingNumbers.includes(`${base}-${n}`)) n += 1
  return `${base}-${n}`
}

/**
 * Nash, 2026-09-12: "a free driver should not see any invoices. Only a pro
 * driver can see those things." The driver's OWN plan decides whether the
 * invoice/expense tools are visible to him at all; the assignment owner's
 * plan decides who may create (canUseBusinessTools).
 */
export function driverCanSeeInvoices(driverPlan: PlanName): boolean {
  return canUseBusinessTools(driverPlan)
}

/* ----------------------------- Expenses ----------------------------- */

/** Article §13. */
export const EXPENSE_CATEGORIES = [
  'Fuel',
  'Tolls',
  'Hotel',
  'Food',
  'Vehicle maintenance',
  'Tire repair',
  'Equipment',
  'Flags',
  'Signs',
  'Lights',
  'Parking',
  'Communication',
  'Other',
] as const
export type ExpenseCategory = (typeof EXPENSE_CATEGORIES)[number]

export interface ExpenseLike {
  category: ExpenseCategory
  amount: number
  billable: boolean
  includeOnInvoice: boolean
}

/** Nash: "a basic report, expense summary, what kind of expenses that trip had." */
export function expenseSummary(expenses: ExpenseLike[]) {
  const byCategory = new Map<ExpenseCategory, { count: number; total: number }>()
  for (const e of expenses) {
    const cur = byCategory.get(e.category) ?? { count: 0, total: 0 }
    byCategory.set(e.category, { count: cur.count + 1, total: round2(cur.total + (e.amount || 0)) })
  }
  return {
    total: round2(expenses.reduce((a, e) => a + (e.amount || 0), 0)),
    billable: round2(expenses.filter((e) => e.billable).reduce((a, e) => a + (e.amount || 0), 0)),
    onInvoice: round2(expenses.filter((e) => e.includeOnInvoice).reduce((a, e) => a + (e.amount || 0), 0)),
    byCategory: [...byCategory.entries()].map(([category, v]) => ({ category, ...v })),
  }
}

/* ------------------------ Recipients & broker ------------------------ */

/** Article §34 list + `carrier_driver` (Nash, 2026-09-12: the carrier driver may be the inviter). */
export type RecipientType = 'carrier_dispatch' | 'carrier_driver' | 'pilot_driver' | 'pilot_company' | 'broker' | 'custom'

/**
 * Article §16 + Nash, 2026-09-12: "Broker will not see the invoices from the
 * pilot… If the broker is the one that invited the pilot, then yes. Or if the
 * pilot invited the broker, yes."
 */
export function brokerCanSeePilotInvoices(input: {
  pilotInvitedByBroker: boolean
  brokerInvitedByPilot: boolean
}): boolean {
  return input.pilotInvitedByBroker || input.brokerInvitedByPilot
}

/** Article §33 subject line. */
export function invoiceEmailSubject(tripRef: string, ownerName: string): string {
  return `Invoice for Pilot Assignment - ${tripRef} - ${ownerName}`
}
