// ============================================================
// QBE Adaptive Web — 11-stage agentic car-insurance flow
//
// The user enters having already clicked "Get a car insurance
// quote" on the QBE homepage, so the orchestrator seeds the
// experience at PRODUCT_TYPE. Each stage pairs an agent chat
// message with a right-pane view; the split-panel layout
// (ChatPanel left, stage view right) stays intact at every step.
// ============================================================

const STAGES = [
  'INTRO',
  'PRODUCT_TYPE',
  'VEHICLE',
  'VEHICLE_CONFIRM',
  'GARAGE',
  'USAGE',
  'MAIN_DRIVER',
  'OTHER_DRIVERS',
  'QUOTE',
  'CHECKOUT',
  'CONFIRMATION',
];

// The 4-step progress rail pinned to the top of every right-pane view.
const PROGRESS_STEPS = ['Your Car', 'Car Usage', 'Drivers', 'Your Quote'];

// Stage → progress-rail step index (0–3).
const STAGE_TO_PROGRESS = {
  PRODUCT_TYPE:    0,
  VEHICLE:         0,
  VEHICLE_CONFIRM: 0,
  GARAGE:          0,
  USAGE:           1,
  MAIN_DRIVER:     2,
  OTHER_DRIVERS:   2,
  QUOTE:           3,
  CHECKOUT:        3,
  CONFIRMATION:    3,
};

// The live-price banner shows from USAGE onwards — we have enough
// signal to price even a rough estimate.
const STAGES_WITH_LIVE_PRICE = new Set(['USAGE', 'MAIN_DRIVER', 'OTHER_DRIVERS', 'QUOTE']);

// Product catalogue — four tiers shown on PRODUCT_TYPE; QUOTE re-uses
// the Comprehensive / ThirdParty base prices for live pricing.
const PRODUCTS = [
  {
    key: 'Comprehensive',
    label: 'Comprehensive',
    desc: 'Full cover for your car and others.',
    from: 124,
    iconKey: 'carShield',
    preselected: true,
  },
  {
    key: 'ThirdPartyProperty',
    label: 'Third Party Property',
    desc: 'Damage you cause to others.',
    from: 42,
    iconKey: 'cardNo',
    preselected: false,
  },
  {
    key: 'CTP',
    label: 'CTP (Greenslip)',
    desc: 'Mandatory injury cover.',
    fromLabel: 'Varies by state',
    iconKey: 'docCar',
    preselected: false,
  },
  {
    key: 'Motorcycle',
    label: 'Motorcycle',
    desc: 'Separate product for bikes.',
    from: 68,
    iconKey: 'motorcycle',
    preselected: false,
  },
];

// Price contributions for each optional extra in QuoteView ($/month).
const EXTRAS = [
  { key: 'Roadside Assist',           price: 11 },
  { key: 'Hire car after accident',   price:  7 },
  { key: 'Windscreen & glass cover',  price:  4 },
  { key: 'Protected No-Claim Discount', price: 6, preselected: true },
];

// Excess tick values shown on the QuoteView slider.
const EXCESS_TICKS = [500, 800, 1100, 1500, 2000];

// Default quote state — seeded at orchestrator mount, mutated live by
// the user's choices in USAGE and QUOTE.
const DEFAULT_QUOTE = {
  tier:           'Comprehensive',       // 'Comprehensive' | 'ThirdPartyProperty'
  excess:         800,
  sumInsured:     28500,
  extras:         ['Protected No-Claim Discount'],
  frequency:      'monthly',             // 'monthly' | 'annual'
  budgetDiscount: 0,                     // $/mo — set by the budget-negotiation flow
};

// Mock NEVDIS lookup result — returned after the "Connecting to NEVDIS..."
// tool-call. Matches the spec copy.
const VEHICLE_LOOKUP_RESULT = {
  year:         2020,
  make:         'Volkswagen',
  model:        'Golf',
  engine:       '1.4L',
  body:         '5D Hatchback',
  seats:        5,
  displayTitle: '2020 Volkswagen Golf',
  chatSummary:  '2020 Volkswagen Golf 1.4L hatchback',
};

// Mock address result used in GARAGE reasoning panel.
const GARAGE_MOCK_ADDRESS = {
  line:      '22 Sydney Street, Rose Bay NSW 2029',
  suburb:    'Rose Bay',
  state:     'NSW',
  postcode:  '2029',
  reasoning: 'Rose Bay, NSW 2029 · Low-risk suburb · Minor flood exposure noted',
};

// ---------------------------------------------------------------
// Live price math — intentionally simple. Not actuarially real;
// just reactive enough that tier / excess / frequency / extras
// each nudge the headline price.
// ---------------------------------------------------------------

// Base monthly premiums per tier at the reference configuration
// (excess $800, sum insured $28,500, no extras, monthly pay).
const TIER_BASE_MONTHLY = {
  Comprehensive:      163.93,   // matches the QuoteView headline in the spec
  ThirdPartyProperty:  62.40,
};

// Higher excess → lower premium. Values are $/month adjustments
// applied to the base.
const EXCESS_ADJUSTMENT = {
   500:  12,
   800:   0,
  1100:  -9,
  1500: -18,
  2000: -26,
};

function computePrice({ tier, excess, sumInsured, extras, frequency, budgetDiscount = 0 }) {
  const base = TIER_BASE_MONTHLY[tier] ?? TIER_BASE_MONTHLY.Comprehensive;
  const excessAdj = EXCESS_ADJUSTMENT[excess] ?? 0;
  // Sum-insured swing: ±$14/mo across a 50% swing from $28.5k baseline.
  const sumAdj = ((sumInsured - 28500) / 28500) * 14;
  const extrasMap = Object.fromEntries(EXTRAS.map(e => [e.key, e.price]));
  const extrasTotal = (extras || []).reduce((s, x) => s + (extrasMap[x] || 0), 0);

  const monthly = Math.max(24, +(base + excessAdj + sumAdj + extrasTotal - (budgetDiscount || 0)).toFixed(2));
  // Annual payment gets a ~4% discount.
  const annual  = +(monthly * 12 * 0.96).toFixed(2);

  return {
    monthly,
    annual,
    displayed: frequency === 'annual' ? annual : monthly,
    unit:      frequency === 'annual' ? 'year'  : 'mo',
  };
}

// Budget-negotiation planner. Given the current quote and a target monthly
// premium, pick an excess tick + budgetDiscount combination that lands at
// (or just below) the target. Used by the QUOTE stage's conversational
// "outside my budget" flow.
//
// Strategy: iterate excess ticks from highest → lowest (never below current
// excess). Pick the largest excess where priceAtTick > target — that way
// the discount needed to close the gap is always positive. If no tick
// qualifies (target is above the current price), fall back to the current
// excess and let the discount do the work alone.
//
// Returns { kind, excess, budgetDiscount, achievedPrice }
//   kind: 'already-under'       — target >= current price, no adjustment needed
//         'excess-plus-discount' — both levers moved
//         'discount-only'        — excess unchanged, discount alone closes the gap
function planBudgetAdjustment(quote, target) {
  const baseQuote = { ...quote, budgetDiscount: 0 };
  const currentPrice = computePrice(baseQuote).monthly;

  if (target >= currentPrice) {
    return { kind: 'already-under', currentPrice };
  }

  const ticksDesc = [...EXCESS_TICKS].sort((a, b) => b - a);
  let bestExcess = quote.excess;
  let bestPrice  = currentPrice;

  for (const excess of ticksDesc) {
    if (excess < quote.excess) continue;  // never lower excess
    const priceAt = computePrice({ ...baseQuote, excess }).monthly;
    if (priceAt > target) {
      bestExcess = excess;
      bestPrice  = priceAt;
      break;
    }
  }

  const budgetDiscount = +(bestPrice - target).toFixed(2);
  const kind = bestExcess !== quote.excess ? 'excess-plus-discount' : 'discount-only';

  return { kind, excess: bestExcess, budgetDiscount, achievedPrice: target };
}

// ---------------------------------------------------------------
// Agent chat copy per stage. Terse, sentence case, no exclamations.
// "chips" is an array of quick-replies rendered under the bubble;
// "widget" is an inline input widget rendered in the chat column
// (VEHICLE's rego+state pair, GARAGE's address autocomplete).
// ---------------------------------------------------------------

const STAGE_MESSAGES = {
  PRODUCT_TYPE: {
    content: "What kind of cover are you after?",
    chips:   ['Comprehensive', 'Third Party Property', 'CTP (Greenslip)', 'Motorcycle'],
  },
  VEHICLE: {
    content: "What’s the rego and state?",
    widget:  'rego-state',
  },
  VEHICLE_CONFIRM: {
    content: "Got it — 2020 Volkswagen Golf 1.4L hatchback. A few quick checks about the car.",
  },
  GARAGE: {
    content: "Where’s it parked overnight?",
    widget:  'address',
  },
  USAGE: {
    content: "How do you use the Golf?",
  },
  MAIN_DRIVER: {
    content: "Tell me about the main driver.",
  },
  OTHER_DRIVERS: {
    content: "Anyone else driving?",
    chips:   ['Just me', 'Add another driver'],
  },
  QUOTE: {
    content: "Here’s your quote. You can adjust anything live and see the price move.",
    chips:   ['Outside my budget'],
  },
  CHECKOUT: {
    content: "Last few details and you’re protected. Fill in the form on the right — I’ll be here if you need anything.",
  },
  CONFIRMATION: {
    content: "You’re covered. Your Certificate of Currency is on its way to your inbox.",
  },
};

// Stage → view component name.
const STAGE_VIEW = {
  PRODUCT_TYPE:    'ProductType',
  VEHICLE:         'VehicleLookup',
  VEHICLE_CONFIRM: 'VehicleConfirm',
  GARAGE:          'Garage',
  USAGE:           'Usage',
  MAIN_DRIVER:     'MainDriver',
  OTHER_DRIVERS:   'OtherDrivers',
  QUOTE:           'Quote',
  CHECKOUT:        'Checkout',
  CONFIRMATION:    'Confirmation',
};

Object.assign(window, {
  STAGES,
  PROGRESS_STEPS,
  STAGE_TO_PROGRESS,
  STAGES_WITH_LIVE_PRICE,
  PRODUCTS,
  EXTRAS,
  EXCESS_TICKS,
  DEFAULT_QUOTE,
  VEHICLE_LOOKUP_RESULT,
  GARAGE_MOCK_ADDRESS,
  computePrice,
  planBudgetAdjustment,
  STAGE_MESSAGES,
  STAGE_VIEW,
});
