// Romanowski Studio — Estimator (v3, wired to new pricing engine)
// Engine globals on window: SERVICE_DEFINITIONS, ENSEMBLE_OPTIONS, ENSEMBLE_LABELS,
// SCORE_PREP_RATES, CREATIVE_RATES, INSTRUMENT_LIST, PRINT_RATES,
// TRANSPOSITION_BASE_RATE, getAudioCreativeRate, calcEffectiveInstrumentCount,
// calcQuote, validateServiceInputs, formatGBP, deadlineToUrgency, checkAdvisory,
// CREATIVE_INSTRUMENT_WEIGHTS

// ── Formspree endpoint — sign up at https://formspree.io, create a form,
//     and paste your form ID below (the bit after /f/ in the endpoint URL).
//     Leave as "YOUR_FORM_ID" and the form will fall back to a mailto.
const FORMSPREE_ID = "YOUR_FORM_ID";

// ── Save / email actions ────────────────────────────────────────────────
function savePdf() { window.print(); }

function quoteAsPlainText(quote, urgency) {
  const fmt = window.formatGBP;
  const lines = [];
  lines.push("ROMANOWSKI STUDIO — INDICATIVE QUOTE");
  lines.push("");
  lines.push("SERVICES");
  quote.lineItems.forEach(li => {
    lines.push(`  ${li.label}${!li.isPrimary && quote.bundleActive && li.bundleDiscountAmount > 0 ? "  (−30% bundled)" : ""}    ${fmt(li.lineTotal)}`);
    if (li.serviceId === "printing" && li._printDetail) {
      const d = li._printDetail;
      const bind = { none: "Loose pages", staple: "Staple bound", tape: "Tape bound", coil: "Coil / comb bound" };
      if (d.conductorPrint > 0)   lines.push(`      Conductor score — printing    ${fmt(d.conductorPrint)}`);
      if (d.conductorBinding > 0) lines.push(`      Conductor score — ${bind[d.condBindLabel] || "binding"}    ${fmt(d.conductorBinding)}`);
      if (d.partsPrint > 0)       lines.push(`      Parts — printing    ${fmt(d.partsPrint)}`);
      if (d.partsBinding > 0)     lines.push(`      Parts — ${bind[d.partsBindLabel] || "binding"}    ${fmt(d.partsBinding)}`);
      if (d.handling > 0)         lines.push(`      Handling & set-up    ${fmt(d.handling)}`);
      if (d.urgencyMult > 1)      lines.push(`      Rush service (×${d.urgencyMult})    ${fmt(window.round2(d.printSubtotal * d.urgencyMult - d.printSubtotal))}`);
    }
  });
  if (quote.bundleActive && quote.totalDiscountGiven > 0) lines.push(`  Multi-service saving    −${fmt(quote.totalDiscountGiven)}`);
  if (quote.studentDiscountActive && quote.studentDiscountAmount > 0) lines.push(`  Student discount (−10%)    −${fmt(quote.studentDiscountAmount)}`);
  if (quote.shippingCost > 0) lines.push(`  Shipping & delivery${quote.shippingLabel ? ` (${quote.shippingLabel})` : ""}    +${fmt(quote.shippingCost)}`);
  lines.push("");
  lines.push(`TOTAL    ${fmt(quote.grandTotal)}`);
  lines.push(`Turnaround: ${urgency}`);
  lines.push("");
  lines.push("Indicative only. Final quote issued on submission of materials.");
  lines.push("— Romanowski Studio  ·  studio@romanowski.studio");
  return lines.join("\n");
}

function emailQuote(quote, urgency) {
  const body    = quoteAsPlainText(quote, urgency);
  const subject = `Romanowski Studio — quote ${window.formatGBP(quote.grandTotal)}`;
  window.location.href = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
}

async function sendQuoteToStudio({ quote, urgency, email, name }) {
  const body = quoteAsPlainText(quote, urgency);
  if (FORMSPREE_ID && FORMSPREE_ID !== "YOUR_FORM_ID") {
    const res = await fetch(`https://formspree.io/f/${FORMSPREE_ID}`, {
      method: "POST",
      headers: { "Content-Type": "application/json", "Accept": "application/json" },
      body: JSON.stringify({
        email,
        name: name || "",
        _subject: `Quote request from ${name || email} — ${window.formatGBP(quote.grandTotal)}`,
        _replyto: email,
        total: window.formatGBP(quote.grandTotal),
        turnaround: urgency,
        quote: body,
      }),
    });
    if (!res.ok) throw new Error(`Send failed (${res.status})`);
    return { method: "formspree" };
  }
  // Fallback: open the visitor's mail client, addressed to the studio,
  // with their email in the body so the studio can reply.
  const subject = `Quote request — ${window.formatGBP(quote.grandTotal)}`;
  const fullBody = `From: ${name ? name + " " : ""}<${email}>\n\n${body}`;
  window.location.href = `mailto:studio@mrmusicstudio.com?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(fullBody)}`;
  return { method: "mailto" };
}

function Estimator() {
  const [services, setServices]     = React.useState(() => ({}));
  const [urgency, setUrgency]       = React.useState("standard");
  const [deadline, setDeadline]     = React.useState("");
  const [studentDiscount, setStudentDiscount] = React.useState(false);
  const [showDebug, setShowDebug]   = React.useState(false);
  const [emailOpen, setEmailOpen]   = React.useState(false);
  const summaryPalette = "olive";

  React.useEffect(() => {
    if (!deadline) return;
    const u = window.deadlineToUrgency(deadline);
    if (u) setUrgency(u);
  }, [deadline]);

  const toggleService = (id) => {
    setServices(prev => {
      const next = { ...prev };
      if (next[id]) { delete next[id]; return next; }
      next[id] = defaultInputs(id);
      return next;
    });
  };

  const updateInput = (id, patch) =>
    setServices(prev => ({ ...prev, [id]: { ...prev[id], ...patch } }));

  const selected = Object.entries(services).map(([serviceId, inputs]) => ({ serviceId, inputs }));

  // Validate & calc
  const allErrors = {};
  let hasErrors = false;
  selected.forEach(s => {
    const errs = window.validateServiceInputs(s.serviceId, s.inputs);
    if (errs.length) { allErrors[s.serviceId] = errs; hasErrors = true; }
  });

  let quote = null;
  if (selected.length && !hasErrors) {
    try { quote = window.calcQuote(selected, urgency, { studentDiscount }); } catch (e) { console.error(e); }
  }

  // Carry the live estimate over to the Submit page (attached to the request).
  const goToSubmit = () => {
    try {
      if (quote) {
        localStorage.setItem("rs_estimate", JSON.stringify({
          total: window.formatGBP(quote.grandTotal),
          turnaround: urgency,
          services: quote.lineItems.map(li => li.label),
          detail: quoteAsPlainText(quote, urgency),
          ts: Date.now(),
        }));
      } else {
        localStorage.removeItem("rs_estimate");
      }
    } catch (e) {}
    window.__go && window.__go("submit");
  };

  return (
    <div className="est-v2">
      <div className="est-v2-form">

        <EstStep num="01" title="Select services">
          <div className="est-svc-grid">
            {window.SERVICE_DEFINITIONS.map(def => (
              <button
                key={def.id}
                type="button"
                className={`est-svc-card ${services[def.id] ? "on" : ""}`}
                onClick={() => toggleService(def.id)}
              >
                <div className="est-svc-num">{def.id.replace(/_/g, " ")}</div>
                <div className="est-svc-name">{def.label}</div>
                <div className="est-svc-desc">{def.description}</div>
              </button>
            ))}
          </div>
        </EstStep>

        {selected.length > 0 && (
          <EstStep num="02" title="Project details">
            <div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
              {selected.map(s => (
                <ServicePanel
                  key={s.serviceId}
                  serviceId={s.serviceId}
                  inputs={s.inputs}
                  update={(patch) => updateInput(s.serviceId, patch)}
                  errors={allErrors[s.serviceId] || []}
                />
              ))}
            </div>
          </EstStep>
        )}

        {selected.length > 0 && (
          <EstStep num="03" title="Turnaround">
            <div className="est-row2">
              <div className="est-subfield">
                <label>Needed by (optional)</label>
                <input type="date" value={deadline} onChange={e => setDeadline(e.target.value)} />
              </div>
              <div className="est-subfield">
                <label>Required turnaround</label>
                <select value={urgency} onChange={e => setUrgency(e.target.value)}>
                  <option value="standard">Standard · 5–10 working days</option>
                  <option value="rush">Rush · 24–72 hours (+50%)</option>
                  <option value="emergency">Same-day / Emergency (+100%)</option>
                </select>
              </div>
            </div>
          </EstStep>
        )}

        {selected.length > 0 && (
          <EstStep num="04" title="Student discount">
            <label className="est-check">
              <input type="checkbox" checked={studentDiscount}
                onChange={e => setStudentDiscount(e.target.checked)} />
              <span>I am a student — apply 10% discount (valid student ID required)</span>
            </label>
          </EstStep>
        )}
      </div>

      <aside className={`est-v2-summary est-sp-${summaryPalette}`} data-summary-palette={summaryPalette}>

        <div className="mono-sm est-summary-label">Your estimate</div>

        {!selected.length && (
          <>
            <div style={{ fontFamily: "var(--serif)", fontStyle:"italic", fontSize: 42, lineHeight: 1.1, marginTop: 24 }}>
              Select a service<br/>to begin.
            </div>
            <div className="mono-sm" style={{ marginTop: 16, opacity: 0.55 }}>
              Your quote builds live as you answer.
            </div>
          </>
        )}

        {selected.length > 0 && hasErrors && (
          <div style={{ marginTop: 24 }}>
            <div className="mono-sm" style={{ opacity: 0.6 }}>Complete the fields left to see a quote.</div>
          </div>
        )}

        {quote && <QuoteSummary quote={quote} inputsByService={services} showDebug={showDebug} setShowDebug={setShowDebug} />}

        <div className="est-cta-group">
          <button className="est-cta" onClick={goToSubmit}>
            <span>Submit for final quote</span>
            <span>→</span>
          </button>
          {quote && (
            <>
              <div className="est-cta-row">
                <button type="button" className="est-cta-ghost" onClick={() => savePdf()} title="Opens print dialog — choose 'Save as PDF'">
                  <span>Save / Print</span>
                </button>
                <button type="button" className="est-cta-ghost" onClick={() => setEmailOpen(o => !o)} title="Send a copy of this quote to your inbox">
                  <span>{emailOpen ? "Cancel" : "Email me a copy"}</span>
                </button>
              </div>
              {emailOpen && (
                <EmailCapture
                  quote={quote}
                  urgency={urgency}
                  onClose={() => setEmailOpen(false)}
                />
              )}
            </>
          )}
        </div>
      </aside>
    </div>
  );
}

function EstStep({ num, title, children }) {
  return (
    <div className="est-step">
      <div className="est-step-head">
        <span className="mono est-step-num">{num}</span>
        <span className="est-step-title">{title}</span>
      </div>
      <div className="est-step-body">{children}</div>
    </div>
  );
}

function defaultInputs(serviceId) {
  if (serviceId === "audio_transcription") {
    return {
      minutes: 0, bpm: 120, beatsPerBar: 4,
      instrumentCount: 1, instruments: [],
      recordingClarity: "clean", outputFormat: "notation",
      jinglePremium: false, additionalDetails: "",
    };
  }
  if (serviceId === "transposition") {
    return {
      bars: 0,
      instrumentCount: 1, instruments: [],
      additionalDetails: "",
    };
  }
  if (serviceId === "printing") {
    return {
      conductorFormat: "a3",
      conductorPages: 0, conductorCopies: 1,
      conductorPaperType: "white",
      conductorBinding: "none",
      parts: [],
      partsPaperType: "white",
      partsBinding: "staple",
      delivery: "uk",
      additionalDetails: "",
    };
  }
  const def  = window.SERVICE_DEFINITIONS.find(s => s.id === serviceId);
  const base = { ensembleSize: "small", additionalDetails: "" };
  def.quantityInputs.forEach(f => { base[f.id] = 0; });
  if (def.qualityInput) {
    base[def.qualityInput.id] = def.qualityInput.type === "checkbox" ? true : def.qualityInput.default;
  }
  if (def.hasOrchestrationPremium)  base.orchestrationPremium = false;
  if (def.hasJinglePremium)         base.jinglePremium = false;
  return base;
}

function ServicePanel({ serviceId, inputs, update, errors }) {
  const def = window.SERVICE_DEFINITIONS.find(s => s.id === serviceId);
  return (
    <div className="est-panel">
      <div className="est-panel-head">
        <div className="mono est-panel-tag">{def.id.replace(/_/g, " ")}</div>
        <div className="est-panel-title">{def.label}</div>
      </div>
      <div className="est-panel-body">
        {serviceId === "printing"            ? <PrintingPanel inputs={inputs} update={update} />
         : serviceId === "audio_transcription" ? <AudioPanel inputs={inputs} update={update} />
         : serviceId === "transposition"       ? <TranspositionPanel def={def} inputs={inputs} update={update} />
         : <StandardPanel def={def} inputs={inputs} update={update} />}
        {serviceId !== "printing" && <DetailsToggle inputs={inputs} update={update} />}
      </div>
      {errors.length > 0 && (
        <div className="est-panel-err">
          {errors.map((e, i) => <div key={i}>— {e}</div>)}
        </div>
      )}
    </div>
  );
}

function DetailsToggle({ inputs, update }) {
  const [open, setOpen] = React.useState(!!inputs.additionalDetails);
  return (
    <div style={{ marginTop: 4 }}>
      <label className="est-check">
        <input type="checkbox" checked={open} onChange={e => { setOpen(e.target.checked); if (!e.target.checked) update({ additionalDetails: "" }); }} />
        <span>Add additional notes for this service</span>
      </label>
      {open && (
        <textarea
          rows="3"
          value={inputs.additionalDetails || ""}
          onChange={e => update({ additionalDetails: e.target.value })}
          placeholder="Any additional requirements or notes…"
          style={{
            width: "100%", marginTop: 8,
            fontFamily: "var(--sans)", fontSize: 13,
            padding: "10px 12px",
            border: "1px solid var(--rule)", borderRadius: 0,
            background: "var(--bg)", color: "var(--fg)",
            resize: "vertical",
          }}
        />
      )}
    </div>
  );
}

// ── Rate indicator (small inline pill) ────────────────────────────────────────
function RateIndicator({ value, detail }) {
  return (
    <div style={{
      marginTop: 8, padding: "8px 12px",
      background: "rgba(198,93,58,0.06)",
      border: "1px solid var(--accent-soft)",
      fontSize: 12, color: "var(--fg)",
      display: "flex", justifyContent: "space-between", alignItems: "baseline",
      letterSpacing: "0.02em",
    }}>
      <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 15 }}>{value}</span>
      <span style={{ color: "var(--fg-muted)", fontSize: 11, fontFamily: "var(--mono)", letterSpacing: "0.04em" }}>{detail}</span>
    </div>
  );
}

function StandardPanel({ def, inputs, update }) {
  // Compute live rate indicator
  const ens = inputs.ensembleSize || "small";
  let rateValue = null, rateDetail = null;
  if (def.id === "score_prep") {
    const isPrem = !!inputs.orchestrationPremium;
    const r = isPrem ? window.CREATIVE_RATES[ens] : window.SCORE_PREP_RATES[ens];
    rateValue  = `${window.formatGBP(r)}/bar`;
    rateDetail = `${window.ENSEMBLE_LABELS[ens]} · ${isPrem ? "Orchestration premium" : "Prep / engraving"}`;
  } else if (def.useCreativeRates) {
    const r = window.CREATIVE_RATES[ens];
    rateValue  = `${window.formatGBP(r)}/bar`;
    rateDetail = `${window.ENSEMBLE_LABELS[ens]} · creative rate`;
  } else if (def.baseRate != null && !def.noEnsemble) {
    const mult = window.ENSEMBLE_MULTIPLIERS[ens] ?? 1;
    rateValue  = `${window.formatGBP(window.round2(def.baseRate * mult))}/${def.unit}`;
    rateDetail = `${window.ENSEMBLE_LABELS[ens]} · base ${window.formatGBP(def.baseRate)} × ${mult.toFixed(2)}`;
  }

  return (
    <>
      <div className="est-row2">
        {def.quantityInputs.map(f => (
          <div className="est-subfield" key={f.id}>
            <label>{f.label}</label>
            <input type="number" min={f.min ?? 1} step={f.step ?? 1}
              value={inputs[f.id] || ""}
              onChange={e => update({ [f.id]: +e.target.value || 0 })} />
          </div>
        ))}
        {!def.noEnsemble && (
          <div className="est-subfield">
            <label>Ensemble size</label>
            <select value={inputs.ensembleSize || "small"} onChange={e => update({ ensembleSize: e.target.value })}>
              {window.ENSEMBLE_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
            </select>
          </div>
        )}
      </div>

      {rateValue && <RateIndicator value={rateValue} detail={rateDetail} />}

      {def.qualityInput && def.qualityInput.type === "select" && (
        <div className="est-subfield">
          <label>{def.qualityInput.label}</label>
          <select value={inputs[def.qualityInput.id] || def.qualityInput.default}
            onChange={e => update({ [def.qualityInput.id]: e.target.value })}>
            {def.qualityInput.options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>
        </div>
      )}

      {def.hasOrchestrationPremium && (
        <label className="est-check">
          <input type="checkbox" checked={!!inputs.orchestrationPremium}
            onChange={e => update({ orchestrationPremium: e.target.checked })} />
          <span>Orchestration premium — for creative orchestration decisions (switches to creative rate)</span>
        </label>
      )}
      {def.hasJinglePremium && (
        <label className="est-check">
          <input type="checkbox" checked={!!inputs.jinglePremium}
            onChange={e => update({ jinglePremium: e.target.checked })} />
          <span>Jingles, TV or idents (+100% commercial-use premium)</span>
        </label>
      )}
    </>
  );
}

// ── Transposition: bars × instrument count, no ensemble ──────────────────────
function TranspositionPanel({ def, inputs, update }) {
  const addInstrument = (name) => {
    if (!name || (inputs.instruments || []).includes(name)) return;
    update({ instruments: [...(inputs.instruments || []), name] });
  };
  const rmInstrument = (name) =>
    update({ instruments: (inputs.instruments || []).filter(i => i !== name) });

  const rate = window.TRANSPOSITION_BASE_RATE;
  const cnt  = Number(inputs.instrumentCount) || 1;

  return (
    <>
      <div className="est-row2">
        <div className="est-subfield">
          <label>Number of bars</label>
          <input type="number" min="1" step="1" value={inputs.bars || ""}
            onChange={e => update({ bars: +e.target.value || 0 })} />
        </div>
        <div className="est-subfield">
          <label>Total number of instruments</label>
          <input type="number" min="1" step="1" value={inputs.instrumentCount || ""}
            onChange={e => update({ instrumentCount: Math.max(1, +e.target.value || 1) })} />
        </div>
      </div>

      <RateIndicator
        value={`${window.formatGBP(window.round2(rate * cnt))}/bar`}
        detail={`£${rate.toFixed(2)} × ${cnt} instrument${cnt!==1?"s":""} (flat rate, all instruments equal)`}
      />

      <div className="est-subfield">
        <label>Identify instruments (optional — for reference)</label>
        <select value="" onChange={e => { addInstrument(e.target.value); e.target.value = ""; }}>
          <option value="">— Add an instrument —</option>
          {window.INSTRUMENT_LIST.map(g => (
            <optgroup key={g.group} label={g.group}>
              {g.items.map(i => <option key={i} value={i}>{i}</option>)}
            </optgroup>
          ))}
        </select>
        {(inputs.instruments || []).length > 0 && (
          <div className="est-chips" style={{ marginTop: 10 }}>
            {inputs.instruments.map(i => (
              <button type="button" key={i} className="est-chip on" onClick={() => rmInstrument(i)}>
                {i} <span style={{ marginLeft: 6, opacity: 0.7 }}>×</span>
              </button>
            ))}
          </div>
        )}
      </div>
    </>
  );
}

// ── Audio transcription: minutes × bpm / beatsPerBar = bars; tiered MU rate ───
function AudioPanel({ inputs, update }) {
  const addInstrument = (name) => {
    if (!name || (inputs.instruments || []).includes(name)) return;
    update({ instruments: [...(inputs.instruments || []), name] });
  };
  const rmInstrument = (name) =>
    update({ instruments: (inputs.instruments || []).filter(i => i !== name) });

  const minutes = Number(inputs.minutes) || 0;
  const bpm     = Number(inputs.bpm) || 120;
  const beats   = Number(inputs.beatsPerBar) || 4;
  const bars    = beats > 0 ? window.round2((minutes * bpm) / beats) : 0;
  const rawCount= Number(inputs.instrumentCount) || 1;
  const eff     = window.calcEffectiveInstrumentCount(rawCount, inputs.instruments || [], window.CREATIVE_INSTRUMENT_WEIGHTS);
  const ratePerBar = window.getAudioCreativeRate(eff);

  return (
    <>
      <div className="est-row2">
        <div className="est-subfield">
          <label>Length of audio (minutes)</label>
          <input type="number" min="0.5" step="0.5" value={inputs.minutes || ""}
            onChange={e => update({ minutes: +e.target.value || 0 })} />
        </div>
        <div className="est-subfield">
          <label>Total number of instruments / voices</label>
          <input type="number" min="1" step="1" value={inputs.instrumentCount || ""}
            onChange={e => update({ instrumentCount: Math.max(1, +e.target.value || 1) })} />
        </div>
      </div>

      <div className="est-row2">
        <div className="est-subfield">
          <label>Tempo (BPM)</label>
          <input type="number" min="1" step="1" value={inputs.bpm || ""}
            onChange={e => update({ bpm: +e.target.value || 0 })} />
        </div>
        <div className="est-subfield">
          <label>Time signature</label>
          <select value={inputs.beatsPerBar || 4} onChange={e => update({ beatsPerBar: +e.target.value })}>
            <option value="2">2 beats per bar (cut time / 2/4)</option>
            <option value="3">3 beats per bar (3/4, 3/8)</option>
            <option value="4">4 beats per bar (4/4)</option>
            <option value="6">6 beats per bar (6/8)</option>
          </select>
        </div>
      </div>

      <RateIndicator
        value={`${window.formatGBP(ratePerBar)}/bar`}
        detail={`Estimated bars: ${bars || "—"} · effective count ${eff.toFixed(1)}`}
      />

      <div className="est-subfield">
        <label>Identify instruments (optional — Piano ×1.5, Harp ×1.3, Organ ×1.75)</label>
        <select value="" onChange={e => { addInstrument(e.target.value); e.target.value = ""; }}>
          <option value="">— Add an instrument —</option>
          {window.INSTRUMENT_LIST.map(g => (
            <optgroup key={g.group} label={g.group}>
              {g.items.map(i => <option key={i} value={i}>{i}</option>)}
            </optgroup>
          ))}
        </select>
        {(inputs.instruments || []).length > 0 && (
          <div className="est-chips" style={{ marginTop: 10 }}>
            {inputs.instruments.map(i => (
              <button type="button" key={i} className="est-chip on" onClick={() => rmInstrument(i)}>
                {i} <span style={{ marginLeft: 6, opacity: 0.7 }}>×</span>
              </button>
            ))}
          </div>
        )}
      </div>

      <div className="est-row2">
        <div className="est-subfield">
          <label>Recording quality (informational)</label>
          <select value={inputs.recordingClarity} onChange={e => update({ recordingClarity: e.target.value })}>
            <option value="clean">Clean studio recording</option>
            <option value="live">Live or rehearsal recording</option>
            <option value="noisy">Low quality / noisy audio</option>
          </select>
        </div>
        <div className="est-subfield">
          <label>Output format</label>
          <select value={inputs.outputFormat} onChange={e => update({ outputFormat: e.target.value })}>
            <option value="notation">Music notation · ×1.0</option>
            <option value="midi">MIDI only · −15%</option>
            <option value="both">Both notation + MIDI · +30%</option>
          </select>
        </div>
      </div>

      <label className="est-check">
        <input type="checkbox" checked={!!inputs.jinglePremium}
          onChange={e => update({ jinglePremium: e.target.checked })} />
        <span>Jingles, TV or idents (+100% commercial-use premium)</span>
      </label>
    </>
  );
}

// ── Printing — A3/A4 conductor, dynamic parts with sided ─────────────────────
function PrintingPanel({ inputs, update }) {
  const updateParts = (fn) => update({ parts: fn(inputs.parts || []) });
  const addPart = () => updateParts(p => [...p, { name: "", pages: 0, copies: 1 }]);
  const updPart = (i, patch) => updateParts(p => p.map((x, j) => j === i ? { ...x, ...patch } : x));
  const rmPart  = (i) => updateParts(p => p.filter((_, j) => j !== i));

  // Conductor binding options — A3 has no staple
  const condBindingOptions = inputs.conductorFormat === "a4"
    ? [
        { value: "none",   label: "None — loose pages" },
        { value: "staple", label: "Staple bound (+£1.50)" },
        { value: "tape",   label: "Tape bound (+£2.00)" },
        { value: "coil",   label: "Coil / comb bound (+£4.00)" },
      ]
    : [
        { value: "none", label: "None — loose pages" },
        { value: "tape", label: "Tape bound (+£3.00)" },
        { value: "coil", label: "Coil / comb bound (+£5.50)" },
      ];

  // If user switches A4→A3 with staple selected, fall back to none
  React.useEffect(() => {
    if (inputs.conductorFormat === "a3" && inputs.conductorBinding === "staple") {
      update({ conductorBinding: "none" });
    }
  }, [inputs.conductorFormat]);

  return (
    <>
      <div className="mono est-subhead">Conductor score</div>
      <div style={{
        fontFamily: "var(--mono)", fontSize: 11, letterSpacing: "0.04em",
        color: "var(--fg-muted)", marginTop: -4, marginBottom: 8,
      }}>
        * All documents are printed double-sided as standard.<br />
        ** Binding is charged per copy.
      </div>
      <div className="est-row2">
        <div className="est-subfield">
          <label>Format</label>
          <select value={inputs.conductorFormat || "a3"} onChange={e => update({ conductorFormat: e.target.value })}>
            <option value="a3">A3 (standard conductor score)</option>
            <option value="a4">A4</option>
          </select>
        </div>
        <div className="est-subfield">
          <label>Total number of pages</label>
          <input type="number" min="0" value={inputs.conductorPages || ""}
            onChange={e => update({ conductorPages: +e.target.value || 0 })} />
          <span className="est-field-hint">
            Printed double-sided{Number(inputs.conductorPages) > 0
              ? ` · ${Math.ceil(Number(inputs.conductorPages) / 2)} sheet${Math.ceil(Number(inputs.conductorPages) / 2) !== 1 ? "s" : ""} per copy`
              : ""}
          </span>
        </div>
        <div className="est-subfield">
          <label>Copies</label>
          <input type="number" min="1" value={inputs.conductorCopies || 1}
            onChange={e => update({ conductorCopies: Math.max(1, +e.target.value || 1) })} />
        </div>
        <div className="est-subfield">
          <label>Paper</label>
          <select value={inputs.conductorPaperType} onChange={e => update({ conductorPaperType: e.target.value })}>
            <option value="white">White 120gsm</option>
            <option value="cream">Cream 120gsm (+£0.12/page)</option>
          </select>
        </div>
        <div className="est-subfield">
          <label>Binding</label>
          <select value={inputs.conductorBinding || "none"} onChange={e => update({ conductorBinding: e.target.value })}>
            {condBindingOptions.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>
        </div>
      </div>

      <div className="mono est-subhead" style={{ marginTop: 24 }}>Individual parts (A4)</div>
      <div className="est-row2">
        <div className="est-subfield">
          <label>Paper (all parts)</label>
          <select value={inputs.partsPaperType} onChange={e => update({ partsPaperType: e.target.value })}>
            <option value="white">White 120gsm</option>
            <option value="cream">Cream 120gsm (+£0.12/page)</option>
          </select>
        </div>
        <div className="est-subfield">
          <label>Binding (all parts)</label>
          <select value={inputs.partsBinding} onChange={e => update({ partsBinding: e.target.value })}>
            <option value="none">None — loose pages</option>
            <option value="staple">Staple (+£1.50)</option>
            <option value="tape">Tape (+£2.00)</option>
            <option value="coil">Coil / comb (+£4.00)</option>
          </select>
        </div>
      </div>

      <div className="parts" style={{ marginTop: 12 }}>
        {(inputs.parts || []).length > 0 && (
          <div className="part-row part-row--head" aria-hidden="true">
            <span className="part-head-label">Part name</span>
            <span className="part-head-label">Total pages*</span>
            <span className="part-head-label">Copies</span>
            <span></span>
          </div>
        )}
        {(inputs.parts || []).map((p, i) => (
          <div key={i} className="part-row">
            <input placeholder="e.g. Violin I" value={p.name || ""}
              onChange={e => updPart(i, { name: e.target.value })} />
            <input type="number" min="0" placeholder="0" value={p.pages || ""}
              onChange={e => updPart(i, { pages: +e.target.value || 0 })} />
            <input type="number" min="1" placeholder="1" value={p.copies}
              onChange={e => updPart(i, { copies: Math.max(1, +e.target.value || 1) })} />
            <span className="part-rm" onClick={() => rmPart(i)} title="Remove part">×</span>
          </div>
        ))}
      </div>
      <button type="button" className="part-add" onClick={addPart}>+ Add instrument part</button>

      <div className="est-subfield" style={{ marginTop: 20 }}>
        <label>Delivery</label>
        <select value={inputs.delivery} onChange={e => update({ delivery: e.target.value })}>
          <option value="uk">UK delivery (next-day)</option>
          <option value="europe_usa">International — Europe &amp; USA (tracked &amp; signed)</option>
          <option value="rest_of_world">International — Rest of World (tracked &amp; signed)</option>
        </select>
        <span className="est-field-hint">
          Shipped once the work is complete — timing depends on the turnaround selected above.
        </span>
      </div>

      <div className="est-subfield" style={{ marginTop: 20 }}>
        <label>Any other info</label>
        <textarea
          rows="3"
          value={inputs.additionalDetails || ""}
          onChange={e => update({ additionalDetails: e.target.value })}
          placeholder="Special paper, cover stock, page-turn notes, delivery instructions…"
          style={{
            width: "100%", marginTop: 4,
            fontFamily: "var(--sans)", fontSize: 13,
            padding: "10px 12px",
            border: "1px solid var(--rule)", borderRadius: 0,
            background: "var(--bg)", color: "var(--fg)",
            resize: "vertical",
          }}
        />
      </div>
    </>
  );
}

function QuoteSummary({ quote, inputsByService, showDebug, setShowDebug }) {
  const fmt = window.formatGBP;
  const BIND_LABEL = { none: "Loose pages", staple: "Staple bound", tape: "Tape bound", coil: "Coil / comb bound" };
  const showAdvisory = quote.lineItems.some(li => {
    const inp = inputsByService[li.serviceId];
    return inp && window.checkAdvisory(li.serviceId, inp);
  });
  const volumeActive = quote.lineItems.some(li => li._printDetail?.volumePricingActive);

  const printBreakdown = (li) => {
    const d = li._printDetail;
    if (!d) return null;
    const rows = [];
    if (d.conductorPrint > 0)   rows.push(["Conductor score — printing", d.conductorPrint]);
    if (d.conductorBinding > 0)  rows.push([`Conductor score — ${BIND_LABEL[d.condBindLabel] || "binding"}`, d.conductorBinding]);
    if (d.partsPrint > 0)        rows.push(["Parts — printing", d.partsPrint]);
    if (d.partsBinding > 0)      rows.push([`Parts — ${BIND_LABEL[d.partsBindLabel] || "binding"}`, d.partsBinding]);
    if (d.handling > 0)          rows.push(["Handling & set-up", d.handling]);
    if (d.urgencyMult > 1)       rows.push([`Rush service (×${d.urgencyMult})`, window.round2(d.printSubtotal * d.urgencyMult - d.printSubtotal)]);
    if (li.minimumApplied)       rows.push(["Minimum print fee applied", window.round2(li.preDiscountTotal - li.afterMultipliers)]);
    if (rows.length === 0) return null;
    return (
      <div className="est-print-breakdown">
        {rows.map(([label, amt], i) => (
          <div key={i} className="est-pbd-row">
            <span>{label}</span><span>{fmt(amt)}</span>
          </div>
        ))}
      </div>
    );
  };

  return (
    <>
      <div className="est-price" style={{ marginTop: 12 }}>{fmt(quote.grandTotal)}</div>
      <div className="est-price-note">Indicative · final quote on submission</div>

      <div className="est-summary-rows">
        {quote.lineItems.map(li => (
          <React.Fragment key={li.serviceId}>
            <div className="est-summary-row">
              <span className="k">
                {li.label}
                {!li.isPrimary && quote.bundleActive && li.bundleDiscountAmount > 0 && (
                  <span className="est-bundle-chip">−30%</span>
                )}
              </span>
              <span className="v">{fmt(li.lineTotal)}</span>
            </div>
            {li.serviceId === "printing" && printBreakdown(li)}
          </React.Fragment>
        ))}
        {quote.bundleActive && quote.totalDiscountGiven > 0 && (
          <div className="est-summary-row" style={{ color: "var(--accent)" }}>
            <span className="k">Multi-service saving</span>
            <span className="v">−{fmt(quote.totalDiscountGiven)}</span>
          </div>
        )}
        {quote.studentDiscountActive && quote.studentDiscountAmount > 0 && (
          <div className="est-summary-row" style={{ color: "var(--accent)" }}>
            <span className="k">Student discount (−10%)</span>
            <span className="v">−{fmt(quote.studentDiscountAmount)}</span>
          </div>
        )}
        {quote.shippingCost > 0 && (
          <div className="est-summary-row est-summary-row--ship">
            <span className="k">
              Shipping &amp; delivery
              {quote.shippingLabel && <span className="est-ship-note">{quote.shippingLabel}</span>}
            </span>
            <span className="v">+{fmt(quote.shippingCost)}</span>
          </div>
        )}
      </div>

      {volumeActive && (
        <div className="est-advisory" style={{ marginTop: 12 }}>
          Volume pricing applied — reduced rates for this print run (300+ A4 sheets or 150+ A3 sheets).
        </div>
      )}

      {showAdvisory && (
        <div className="est-advisory">
          Large-scale project — a bespoke quote is recommended. Submit your score for a firm price.
        </div>
      )}
    </>
  );
}

window.Estimator = Estimator;

function EmailCapture({ quote, urgency, onClose }) {
  const [email, setEmail] = React.useState("");
  const [name, setName]   = React.useState("");
  const [status, setStatus] = React.useState("idle"); // idle | sending | sent | error
  const [errMsg, setErrMsg] = React.useState("");

  const submit = async (e) => {
    e.preventDefault();
    if (!email || !/^\S+@\S+\.\S+$/.test(email)) {
      setErrMsg("Please enter a valid email address.");
      setStatus("error");
      return;
    }
    setStatus("sending");
    setErrMsg("");
    try {
      await sendQuoteToStudio({ quote, urgency, email, name });
      setStatus("sent");
    } catch (err) {
      setErrMsg(err.message || "Something went wrong. Try again, or use Save / Print.");
      setStatus("error");
    }
  };

  if (status === "sent") {
    return (
      <div className="est-email-capture est-email-capture--ok">
        <div className="est-email-capture-title">Sent — thanks.</div>
        <div className="est-email-capture-msg">
          A copy of this quote will be in your inbox shortly. The studio will follow up if a firm price needs discussion.
        </div>
        <button type="button" className="est-cta-ghost" onClick={onClose}>Close</button>
      </div>
    );
  }

  return (
    <form className="est-email-capture" onSubmit={submit}>
      <div className="est-email-capture-title">Email me a copy</div>
      <div className="est-email-capture-msg">
        Only used to send you this quote and follow up if needed. No marketing.
      </div>
      <input
        type="email"
        required
        autoFocus
        placeholder="your@email.com"
        value={email}
        onChange={e => setEmail(e.target.value)}
        disabled={status === "sending"}
      />
      <input
        type="text"
        placeholder="Your name (optional)"
        value={name}
        onChange={e => setName(e.target.value)}
        disabled={status === "sending"}
      />
      {status === "error" && <div className="est-email-capture-err">{errMsg}</div>}
      <button type="submit" className="est-cta" disabled={status === "sending"}>
        <span>{status === "sending" ? "Sending…" : "Send to me"}</span>
        {status !== "sending" && <span>→</span>}
      </button>
    </form>
  );
}
window.EmailCapture = EmailCapture;
