import { describe, expect, it } from 'vitest'
import {
  brokerCanSeePilotInvoices,
  calculateInvoice,
  canUseBusinessTools,
  driverCanSeeInvoices,
  DUE_DATE_OPTIONS,
  dueDateFor,
  EXPENSE_CATEGORIES,
  expenseSummary,
  invoiceEmailSubject,
  invoiceOwner,
  LOCKED_PRO_COPY,
  nextInvoiceNumber,
} from '@/lib/domain/invoicing'
import { PLANS } from '@/lib/demo/credits'
import { DEFAULT_TEMPLATES, TEMPLATE_VARIABLES } from '@/lib/email-templates'

/** Pro Tools / invoicing article (2026-09-12) + Nash's answers the same day. */

describe('plans (article §3, §26–§29)', () => {
  it('the $9 plan is Starter, never Pilot; four plans with the same prices', () => {
    expect(PLANS.map((p) => [p.name, p.price])).toEqual([
      ['Free', 0],
      ['Starter', 9],
      ['Pro', 29],
      ['Pro Plus', 59],
    ])
    expect(PLANS.some((p) => p.name === 'Pilot')).toBe(false)
    // Nash, 2026-09-13: Fleet replaced by Pro Plus — no team/shared-plan wording anywhere on the plans.
    expect(PLANS.some((p) => p.name === 'Fleet')).toBe(false)
    const all = PLANS.map((p) => [p.name, p.tagline, p.bestFor, p.positioning ?? '', ...p.includes].join(' ')).join(' ')
    expect(all).not.toMatch(/fleet|company-wide|multi-user|team|shared route|shared AI|multiple users/i)
    const plus = PLANS.find((p) => p.name === 'Pro Plus')!
    expect([plus.price, plus.routes, plus.credits]).toEqual([59, 59, 30])
    expect(plus.includes).toEqual([
      '59 Express Routes per month',
      '$30 AI Credits per month',
      'Everything included in Pro',
      'Future active trip GPS visibility',
      'Future truck/driver location view for active trips',
      'Future assigned pilot car location view during active pilot assignments',
    ])
  })

  it('Pro lists the business tools; Starter does not', () => {
    const pro = PLANS.find((p) => p.name === 'Pro')!
    const starter = PLANS.find((p) => p.name === 'Starter')!
    // Nash, 2026-09-13: Pro lines name their role.
    // Nash, 2026-09-13: pilot paperwork is Starter and up ("anyone Starter plan or above… the files, the alerts, everything") — not a Pro line.
    expect(pro.includes).toContain('Everything included in Starter')
    expect(pro.includes.join(' ')).not.toMatch(/paperwork/i)
    expect(pro.includes).toContain('Pilot companies and pilot drivers: generate invoices for your trips')
    expect(pro.includes).toContain('Pilot drivers: track expenses for the trip')
    expect(pro.includes).toContain('Carrier truck drivers: track expenses for the trip')
    expect(starter.includes.join(' ')).not.toMatch(/invoice|expense/i)
  })

  it('only Pro and Pro Plus unlock invoice and expense tools (§20, §35)', () => {
    expect(canUseBusinessTools('Free')).toBe(false)
    expect(canUseBusinessTools('Starter')).toBe(false)
    expect(canUseBusinessTools('Pro')).toBe(true)
    expect(canUseBusinessTools('Pro Plus')).toBe(true)
  })

  it('locked copy is the article\'s §24 wording', () => {
    expect(LOCKED_PRO_COPY.title).toBe('Create Invoice - Pro Feature')
    expect(LOCKED_PRO_COPY.upgrade).toBe('Upgrade to Pro')
    expect(LOCKED_PRO_COPY.notNow).toBe('Not Now')
  })
})

describe('assignment ownership (§22)', () => {
  it('company-managed → company owns; direct → driver owns', () => {
    expect(invoiceOwner({ managedByCompany: true })).toBe('pilot_company')
    expect(invoiceOwner({ managedByCompany: false })).toBe('pilot_driver')
  })
})

describe('invoice calculation (§9–§11)', () => {
  it('matches the article example: daily wins, overnight added', () => {
    const c = calculateInvoice({ miles: 420, ratePerMile: 1.75, days: 2, dailyRate: 600, overnights: 1, overnightFee: 150, expenseAmounts: [], customAmounts: [] })
    expect(c.mileageTotal).toBe(735)
    expect(c.dailyTotal).toBe(1200)
    expect(c.selectedBaseType).toBe('daily')
    expect(c.selectedBaseTotal).toBe(1200)
    expect(c.overnightTotal).toBe(150)
    expect(c.invoiceTotal).toBe(1350)
    expect(c.explanation).toBe('Daily rate was selected because it is greater than the mileage total.')
  })

  it('never charges both bases; mileage wins when greater', () => {
    const c = calculateInvoice({ miles: 900, ratePerMile: 2, days: 1, dailyRate: 600, overnights: 0, overnightFee: 0, expenseAmounts: [], customAmounts: [] })
    expect(c.selectedBaseType).toBe('mileage')
    expect(c.invoiceTotal).toBe(1800)
  })

  it('adds included expenses and custom line items', () => {
    const c = calculateInvoice({ miles: 0, ratePerMile: 0, days: 1, dailyRate: 500, overnights: 0, overnightFee: 0, expenseAmounts: [42.5, 10], customAmounts: [75] })
    expect(c.expenseTotal).toBe(52.5)
    expect(c.customTotal).toBe(75)
    expect(c.invoiceTotal).toBe(627.5)
  })
})

describe('due date options (Nash, 2026-09-12)', () => {
  it('offers ASAP, 1, 3, 7, 14, 30 and 60 days, optional', () => {
    expect(DUE_DATE_OPTIONS.map((o) => o.label)).toEqual(['ASAP', '1 day', '3 days', '7 days', '14 days', '30 days', '60 days'])
    expect(dueDateFor('2026-09-12', '30')).toBe('2026-10-12')
    expect(dueDateFor('2026-09-12', 'asap')).toBe('2026-09-12')
    expect(dueDateFor('2026-09-12', null)).toBeNull()
  })
})

describe('invoice numbers (Nash: pilot + invoice + trip number + date)', () => {
  it('is PILOT-INV-<trip>-<date>, with a suffix only for a second invoice the same day', () => {
    expect(nextInvoiceNumber([], 'HH-2041', '2026-09-12')).toBe('PILOT-INV-HH-2041-20260912')
    expect(nextInvoiceNumber(['PILOT-INV-HH-2041-20260912'], 'HH-2041', '2026-09-12')).toBe('PILOT-INV-HH-2041-20260912-2')
    expect(nextInvoiceNumber(['PILOT-INV-HH-2041-20260912'], 'HH-2050', '2026-09-12')).toBe('PILOT-INV-HH-2050-20260912')
  })
})

describe('driver visibility (Nash: "a free driver should not see any invoices")', () => {
  it('only a Pro or Pro Plus driver sees invoices', () => {
    expect(driverCanSeeInvoices('Free')).toBe(false)
    expect(driverCanSeeInvoices('Starter')).toBe(false)
    expect(driverCanSeeInvoices('Pro')).toBe(true)
    expect(driverCanSeeInvoices('Pro Plus')).toBe(true)
  })
})

describe('expenses (§13, §25; Nash: basic summary by kind)', () => {
  it('has the thirteen article categories', () => {
    expect(EXPENSE_CATEGORIES).toHaveLength(13)
    expect(EXPENSE_CATEGORIES[0]).toBe('Fuel')
    expect(EXPENSE_CATEGORIES[12]).toBe('Other')
  })

  it('summarises by category, billable and on-invoice', () => {
    const s = expenseSummary([
      { category: 'Fuel', amount: 100, billable: true, includeOnInvoice: true },
      { category: 'Fuel', amount: 50, billable: true, includeOnInvoice: false },
      { category: 'Hotel', amount: 120, billable: false, includeOnInvoice: false },
    ])
    expect(s.total).toBe(270)
    expect(s.billable).toBe(150)
    expect(s.onInvoice).toBe(100)
    expect(s.byCategory).toEqual([
      { category: 'Fuel', count: 2, total: 150 },
      { category: 'Hotel', count: 1, total: 120 },
    ])
  })
})

describe('broker visibility (§16; Nash, 2026-09-12)', () => {
  it('broker sees pilot invoices only when they invited the pilot or the pilot invited them', () => {
    expect(brokerCanSeePilotInvoices({ pilotInvitedByBroker: false, brokerInvitedByPilot: false })).toBe(false)
    expect(brokerCanSeePilotInvoices({ pilotInvitedByBroker: true, brokerInvitedByPilot: false })).toBe(true)
    expect(brokerCanSeePilotInvoices({ pilotInvitedByBroker: false, brokerInvitedByPilot: true })).toBe(true)
  })
})

describe('invoice email (§33; admin-managed template)', () => {
  it('subject follows the article', () => {
    expect(invoiceEmailSubject('HH-2041', 'ABC Pilot Cars')).toBe('Invoice for Pilot Assignment - HH-2041 - ABC Pilot Cars')
  })

  it('ships a pilot_invoice template with a link to the invoice', () => {
    const t = DEFAULT_TEMPLATES.find((x) => x.key === 'pilot_invoice')!
    expect(t.subject).toBe('Invoice for Pilot Assignment - {{trip_id}} - {{pilot_name}}')
    expect(t.body).toContain('{{invoice_link}}')
    expect(t.body).toContain('{{payment_instructions}}')
    expect(TEMPLATE_VARIABLES).toContain('invoice_link')
  })
})

describe('pilot-to-trip invitation templates (Nash, 2026-09-13)', () => {
  it('ships admin-manageable templates for adding a pilot dispatch and an additional pilot', () => {
    const dispatch = DEFAULT_TEMPLATES.find((t) => t.key === 'pilot_dispatch_trip_invite')!
    const pilot = DEFAULT_TEMPLATES.find((t) => t.key === 'pilot_additional_trip_invite')!
    expect(dispatch.name).toBe('Pilot Dispatch Invited to Trip')
    expect(pilot.name).toBe('Additional Pilot Invited to Trip')
    for (const t of [dispatch, pilot]) {
      expect(t.body).toContain('{{signup_link}}')
      expect(t.body).toContain('{{shared_access}}')
      expect(t.body).toContain('{{workspace_link}}')
    }
    expect(TEMPLATE_VARIABLES).toContain('shared_access')
  })
})

describe('pilot paperwork for brokers and carriers (Nash, 2026-09-13)', () => {
  it('Starter or higher is included; Free gets 90 days from sign-up, then locked', async () => {
    const { pilotPaperworkAccess, PAPERWORK_TRIAL_DAYS, PAPERWORK_LOCKED_COPY, PAPERWORK_PURPOSE } = await import('@/lib/domain/invoicing')
    expect(PAPERWORK_TRIAL_DAYS).toBe(90)
    expect(pilotPaperworkAccess({ plan: 'Starter', signedUpAt: '2025-01-01', today: '2026-09-13' })).toEqual({ mode: 'included' })
    expect(pilotPaperworkAccess({ plan: 'Pro', signedUpAt: '2025-01-01', today: '2026-09-13' })).toEqual({ mode: 'included' })
    expect(pilotPaperworkAccess({ plan: 'Pro Plus', signedUpAt: '2025-01-01', today: '2026-09-13' })).toEqual({ mode: 'included' })
    expect(pilotPaperworkAccess({ plan: 'Free', signedUpAt: '2026-09-13', today: '2026-09-13' })).toEqual({ mode: 'trial', daysLeft: 90 })
    expect(pilotPaperworkAccess({ plan: 'Free', signedUpAt: '2026-06-16', today: '2026-09-13' })).toEqual({ mode: 'trial', daysLeft: 1 })
    expect(pilotPaperworkAccess({ plan: 'Free', signedUpAt: '2026-06-15', today: '2026-09-13' })).toEqual({ mode: 'locked' })
    expect(PAPERWORK_LOCKED_COPY.title).toBe('Pilot paperwork - Starter Feature')
    expect(PAPERWORK_LOCKED_COPY.upgrade).toBe('Upgrade to Starter')
    expect(PAPERWORK_PURPOSE).toContain('brokers, carrier dispatchers and drivers')
  })
  it('lists every slot of the account type and alerts on missing required paperwork', async () => {
    const { paperworkList, paperworkAlerts } = await import('@/lib/domain/pilot')
    const docs = paperworkList('pilot_company', [
      { key: 'insurance', status: 'Expiring Soon', expirationDate: '2026-09-25' },
      { key: 'w9', status: 'Uploaded' },
    ])
    expect(docs.map((d) => d.key)).toEqual(['insurance', 'w9', 'business_license', 'good_standing', 'company_documents', 'state_company_certification'])
    expect(docs.find((d) => d.key === 'business_license')?.status).toBe('Not Uploaded')
    expect(paperworkAlerts(docs)).toEqual(['Certificate of insurance expires 2026-09-25', 'Business license missing'])
    const ok = paperworkList('pilot_driver', [
      { key: 'w9', status: 'Uploaded' },
      { key: 'driver_license', status: 'Approved' },
      { key: 'insurance', status: 'Approved' },
      { key: 'pilot_certification', status: 'Approved' },
    ])
    expect(paperworkAlerts(ok)).toEqual([])
  })
  it('the plan cards advertise it: Free 90 days, Starter and up included', async () => {
    const { PLANS } = await import('@/lib/demo/credits')
    const inc = (n: string) => PLANS.find((p) => p.name === n)?.includes.join(' | ') ?? ''
    expect(inc('Free')).toContain('free for your first 90 days')
    expect(inc('Starter')).toContain('Pilot paperwork on your trips')
    expect(inc('Pro')).toContain('Everything included in Starter')
    expect(inc('Pro Plus')).toContain('Everything included in Pro')
  })
})
