// Pricing engine — linear-foot driven with side-panel exceptions
// All prices flow from these defaults; admin can edit them live.

const DEFAULT_PRICING = {
  // Core linear-foot rates
  linear_ft_rate:     { label: 'Standard linear foot rate',  unit: 'per lin. ft', price: 145, note: 'Covers face frames, doors, drawers, shelves, refinishing — the bulk of the work.' },
  toe_kick_rate:      { label: 'Toe kick',                   unit: 'per lin. ft', price: 38,  note: 'Toe kick fabrication & install per linear foot.' },

  // Per-side finished panels (the exception to the linear-ft model)
  side_panel_one:     { label: 'Finished side panel — single (L or R)', unit: 'per cabinet', price: 185, note: 'One finished end panel.' },
  side_panel_both:    { label: 'Finished side panels — both ends',      unit: 'per cabinet', price: 320, note: 'Both ends finished.' },

  // Surcharges
  rush_upcharge_flat:  { label: 'Rush upcharge (flat)',      unit: 'flat',         price: 250, note: 'Added when the order is flagged RUSH (manual or auto-prompted by completion date).' },
  island_surcharge_pct:{ label: 'Island / peninsula surcharge', unit: '% of cabinet line', price: 10, note: 'Applied per cabinet flagged Island or Peninsula.' },

  // Scribe — added at the end of the order
  scribe_matched:     { label: 'Scribe — matched material',  unit: 'per lin. ft', price: 18, note: 'Match the cabinet box material (cost mirrors order materials).' },
  scribe_unmatched:   { label: 'Scribe — cheapest material', unit: 'per lin. ft', price: 9,  note: 'Used when match-material is "No" — uses our cheapest stock.' },

  // Material multipliers (applied to that cabinet's linear-ft line)
  mat_birch:          { label: 'Birch plywood',     unit: 'multiplier', price: 1.00, note: 'Baseline.' },
  mat_maple:          { label: 'Hardrock maple',    unit: 'multiplier', price: 1.18 },
  mat_maple_ply:      { label: 'Maple plywood',     unit: 'multiplier', price: 1.10 },
  mat_cherry:         { label: 'Cherry plywood',    unit: 'multiplier', price: 1.22 },
  mat_oak:            { label: 'Oak plywood',       unit: 'multiplier', price: 1.08 },
  mat_walnut:         { label: 'Walnut plywood',    unit: 'multiplier', price: 1.30 },
  mat_melamine_white: { label: 'Melamine — white',  unit: 'multiplier', price: 0.85 },
  mat_melamine_wood:  { label: 'Melamine — wood-look', unit: 'multiplier', price: 0.90 },
  mat_mdf:            { label: 'MDF',               unit: 'multiplier', price: 0.80 },
  mat_particle:       { label: 'Particle board',    unit: 'multiplier', price: 0.75 },
  mat_other:          { label: 'Other / custom',    unit: 'multiplier', price: 1.00 },

  // Flat fees
  trip_charge:        { label: 'Trip charge',  unit: 'flat', price: 95 },
  minimum_job:        { label: 'Minimum job',  unit: 'flat', price: 350 },
  tax_rate_pct:       { label: 'Tax rate',     unit: '% of subtotal', price: 0 },
};

// Map BOX_MATERIALS dropdown labels → pricing keys
const MATERIAL_KEY_MAP = {
  'Birch plywood': 'mat_birch',
  'Hardrock maple': 'mat_maple',
  'Maple plywood': 'mat_maple_ply',
  'Cherry plywood': 'mat_cherry',
  'Oak plywood': 'mat_oak',
  'Walnut plywood': 'mat_walnut',
  'Melamine — white': 'mat_melamine_white',
  'Melamine — wood-look': 'mat_melamine_wood',
  'MDF': 'mat_mdf',
  'Particle board': 'mat_particle',
  'Other': 'mat_other',
};

// Convert a dimension value+unit to inches
function toInches(val, unit) {
  const v = parseFloat(val);
  if (!v || isNaN(v)) return 0;
  if (unit === 'mm') return v / 25.4;
  return v;
}

// Billable linear feet for a single cabinet:
// Use the cabinet's width in feet as the spine, then add component
// uplifts so a wide cabinet with lots of doors/drawers prices more
// than a wide empty box. Doors / drawers / shelves only contribute
// when the matching `*Repair` flag is true (intake redesign): if a
// vendor isn't asking us to repair the doors, we don't charge for
// them even though they exist.
function cabinetLinearFt(cab) {
  const wIn = toInches(cab.w, cab.wu);
  const widthFt = wIn / 12;
  if (!widthFt) return 0;

  const doors = (cab.doorsRepair === true) ? (parseInt(cab.doors) || 0) : 0;
  const drawers = (cab.drawersRepair === true) ? (parseInt(cab.drawers) || 0) : 0;
  const shelves = (cab.shelvesRepair === true) ? (parseInt(cab.shelves) || 0) : 0;

  // Component uplifts in linear-foot equivalents
  const componentLF = (doors * 0.5) + (drawers * 0.4) + (shelves * 0.25);

  return widthFt + componentLF;
}

// Compute the full estimate for an order
function computeEstimate(data, pricing) {
  const cabinets = data.cabinets || [];
  const tk = data.toeKick || {};
  const linePrice = pricing.linear_ft_rate?.price || 0;
  const tkPrice = pricing.toe_kick_rate?.price || 0;
  const islandPct = (pricing.island_surcharge_pct?.price || 0) / 100;
  const rushFlat = pricing.rush_upcharge_flat?.price || 0;
  const scribeMatchedRate = pricing.scribe_matched?.price || 0;
  const scribeUnmatchedRate = pricing.scribe_unmatched?.price || 0;
  const taxPct = (pricing.tax_rate_pct?.price || 0) / 100;

  const lineItems = [];
  let subtotal = 0;

  // Per-cabinet line items
  for (let i = 0; i < cabinets.length; i++) {
    const c = cabinets[i];
    const lf = cabinetLinearFt(c);
    const matKey = MATERIAL_KEY_MAP[c.boxMaterial];
    const mult = matKey && pricing[matKey] ? pricing[matKey].price : 1;

    let cabBase = lf * linePrice * mult;
    let islandUplift = 0;
    if (c.cabType === 'Island' || c.cabType === 'Peninsula') {
      islandUplift = cabBase * islandPct;
    }
    const cabTotal = cabBase + islandUplift;

    lineItems.push({
      type: 'cabinet',
      label: `Cab ${String(i + 1).padStart(2, '0')}${c.name ? ' — ' + c.name : ''}`,
      detail: `${lf.toFixed(2)} lin. ft × $${linePrice}${mult !== 1 ? ` × ${mult.toFixed(2)} (${c.boxMaterial})` : ''}${islandUplift > 0 ? ` + ${(islandPct * 100).toFixed(0)}% ${c.cabType.toLowerCase()}` : ''}`,
      qty: lf, rate: linePrice * mult, amount: cabTotal,
    });
    subtotal += cabTotal;

    // Finished side panel(s) — separate line
    if (c.finishedSide === 'Yes' && c.finishedWhich) {
      const isBoth = c.finishedWhich === 'Both';
      const sp = isBoth ? pricing.side_panel_both : pricing.side_panel_one;
      if (sp) {
        lineItems.push({
          type: 'side_panel',
          label: `↳ Finished side — ${c.finishedWhich}`,
          detail: sp.label,
          qty: 1, rate: sp.price, amount: sp.price,
        });
        subtotal += sp.price;
      }
    }
  }

  // Toe kick line
  const tkFt = parseFloat(tk.linearFt) || 0;
  if (tkFt > 0) {
    const tkAmount = tkFt * tkPrice;
    lineItems.push({
      type: 'toe_kick',
      label: 'Toe kick',
      detail: `${tkFt} lin. ft × $${tkPrice}${tk.thickness ? ` · ${tk.thickness}` : ''}`,
      qty: tkFt, rate: tkPrice, amount: tkAmount,
    });
    subtotal += tkAmount;
  }

  // Scribe line
  const scribe = data.scribe || {};
  const scribeFt = parseFloat(scribe.linearFeet) || 0;
  if (scribe.needed === 'Yes' && scribeFt > 0) {
    const matched = scribe.matchMaterial !== 'No';
    const rate = matched ? scribeMatchedRate : scribeUnmatchedRate;
    const amt = scribeFt * rate;
    lineItems.push({
      type: 'scribe',
      label: matched ? 'Scribe (matched material)' : 'Scribe (cheapest material)',
      detail: `${scribeFt} lin. ft × $${rate}`,
      qty: scribeFt, rate, amount: amt,
    });
    subtotal += amt;
  }

  // Trip charge
  const trip = pricing.trip_charge?.price || 0;
  if (subtotal > 0 && trip > 0) {
    lineItems.push({ type: 'fee', label: 'Trip charge', detail: 'Flat fee', qty: 1, rate: trip, amount: trip });
    subtotal += trip;
  }

  // Rush upcharge — flat dollars, applied when data.rush === true
  // (vendor manually toggled RUSH or accepted the auto-prompt when
  // their requested completion date was inside the rush window).
  let rushAmount = 0;
  if (subtotal > 0 && data.rush === true && rushFlat > 0) {
    rushAmount = rushFlat;
    lineItems.push({
      type: 'surcharge',
      label: 'Rush upcharge',
      detail: `Flat fee — order flagged RUSH`,
      qty: 1, rate: rushAmount, amount: rushAmount,
    });
    subtotal += rushAmount;
  }

  // Minimum job
  const minimum = pricing.minimum_job?.price || 0;
  let minimumApplied = 0;
  if (subtotal > 0 && subtotal < minimum) {
    minimumApplied = minimum - subtotal;
    lineItems.push({
      type: 'fee',
      label: 'Minimum job adjustment',
      detail: `Brings total to $${minimum} minimum`,
      qty: 1, rate: minimumApplied, amount: minimumApplied,
    });
    subtotal = minimum;
  }

  // Tax
  let tax = 0;
  if (taxPct > 0 && subtotal > 0) {
    tax = subtotal * taxPct;
  }

  const total = subtotal + tax;

  return {
    lineItems,
    subtotal: Math.round(subtotal * 100) / 100,
    tax: Math.round(tax * 100) / 100,
    total: Math.round(total * 100) / 100,
    rushApplied: rushAmount > 0,
    minimumApplied: minimumApplied > 0,
  };
}

function fmtMoney(n) {
  if (n == null || isNaN(n)) return '$0';
  return '$' + Math.round(n).toLocaleString();
}

// Pricing persistence — Firestore primary, localStorage fallback
const PRICING_STORAGE_KEY = 'cabinet_intake_pricing_v1';

function loadPricingLocal() {
  try {
    const raw = localStorage.getItem(PRICING_STORAGE_KEY);
    if (!raw) return DEFAULT_PRICING;
    const saved = JSON.parse(raw);
    const merged = { ...DEFAULT_PRICING };
    for (const k of Object.keys(saved)) {
      if (merged[k]) merged[k] = { ...merged[k], price: saved[k].price };
    }
    return merged;
  } catch { return DEFAULT_PRICING; }
}

async function loadPricingFromFirestore() {
  try {
    const doc = await db.doc('pricing/current').get();
    if (!doc.exists) return loadPricingLocal();
    const saved = doc.data();
    const merged = { ...DEFAULT_PRICING };
    for (const k of Object.keys(saved)) {
      if (merged[k] && typeof saved[k]?.price === 'number') {
        merged[k] = { ...merged[k], price: saved[k].price };
      }
    }
    // Cache locally for offline
    try {
      const slim = {};
      for (const [k, v] of Object.entries(merged)) slim[k] = { price: v.price };
      localStorage.setItem(PRICING_STORAGE_KEY, JSON.stringify(slim));
    } catch {}
    return merged;
  } catch (err) {
    console.warn('Firestore pricing load failed, using local:', err);
    return loadPricingLocal();
  }
}

function loadPricing() {
  return loadPricingLocal();
}

async function savePricing(pricing) {
  // Save locally
  try {
    const slim = {};
    for (const [k, v] of Object.entries(pricing)) slim[k] = { price: v.price };
    localStorage.setItem(PRICING_STORAGE_KEY, JSON.stringify(slim));
  } catch {}
  // Save to Firestore
  try {
    const user = auth.currentUser;
    if (!user) return;
    const update = {};
    for (const [k, v] of Object.entries(pricing)) {
      update[k] = { ...v };
    }
    update.updatedAt = firebase.firestore.FieldValue.serverTimestamp();
    update.updatedBy = user.uid;
    await db.doc('pricing/current').set(update, { merge: true });
  } catch (err) {
    console.warn('Firestore pricing save failed:', err);
  }
}

Object.assign(window, {
  DEFAULT_PRICING, MATERIAL_KEY_MAP, cabinetLinearFt, computeEstimate, fmtMoney, toInches,
  loadPricing, savePricing, loadPricingFromFirestore, loadPricingLocal,
});
