/* NGIPL PLM Quick quote: pick items, adjust rates, download or print.
   Nothing here is saved to the shared database. The draft lives only on this device. */
const { useState, useEffect, useRef } = React;

const QQ_DRAFT_KEY = "plm-quickquote-v1";
const QQ_DEFAULT_NOTE = "Rates valid 30 days from date of quotation.";

function qqLoadDraft() {
  try {
    const raw = localStorage.getItem(QQ_DRAFT_KEY);
    if (!raw) return null;
    const d = JSON.parse(raw);
    if (!d || !Array.isArray(d.items)) return null;
    var items = d.items.filter(function (it) {
      return it && typeof it === "object" && typeof it.productId === "string" && typeof it.rate === "number" && isFinite(it.rate);
    });
    return { customer: typeof d.customer === "string" ? d.customer : "", note: typeof d.note === "string" ? d.note : QQ_DEFAULT_NOTE, items: items };
  } catch (e) { return null; }
}
function qqSaveDraft(d) {
  try { localStorage.setItem(QQ_DRAFT_KEY, JSON.stringify(d)); } catch (e) {}
}
function qqToday() {
  return new Date().toLocaleDateString("en-IN", { day: "numeric", month: "long", year: "numeric" });
}

function QuickQuoteView({ headerStyle, onHeaderStyle, toast }) {
  const state = PLM.useStore();
  const [draft, setDraft] = useState(() => qqLoadDraft() || { customer: "", note: QQ_DEFAULT_NOTE, items: [] });
  const [pickerOpen, setPickerOpen] = useState(false);
  const [confirmClear, setConfirmClear] = useState(false);
  const [pdfBusy, setPdfBusy] = useState(false);
  useEffect(() => { qqSaveDraft(draft); }, [draft]);
  /* Warm html2canvas and jsPDF while items are still being picked, so pressing
     Download in a hotel lobby is not the moment we find the CDN unreachable. */
  const hasItems = draft.items.length > 0;
  useEffect(() => { if (hasItems) loadPdfLibs().catch(() => {}); }, [hasItems]);

  const pb = PLM.productsById();
  const items = draft.items.filter((it) => pb[it.productId]); /* items whose product was deleted drop off */
  const nm = PLM.numberMap();
  const sorted = items.slice().sort((a, b) => {
    const an = nm[a.productId] || 9999, bn = nm[b.productId] || 9999;
    return an - bn;
  });
  const quick = { customer: draft.customer, note: draft.note, date: qqToday(), items: items };

  /* preview scale, same approach as the Print & export desk */
  const deskRef = useRef(null);
  const wrapRef = useRef(null);
  const [fit, setFit] = useState({ scale: 1, h: 0, pages: 1 });
  useEffect(() => {
    function measure() {
      const desk = deskRef.current, wrap = wrapRef.current;
      /* Retry rather than give up: on first paint the sheet child may not exist yet,
         and a single missed frame used to leave the preview stuck at full size. */
      if (!desk || !wrap || !wrap.firstChild || !desk.clientWidth) { raf = requestAnimationFrame(measure); return; }
      const sheet = wrap.firstChild;
      const cs = getComputedStyle(desk);
      const avail = desk.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
      const scale = Math.min(1, avail / 794);
      const h = sheet.offsetHeight;
      /* the sheet is A4 at 96dpi, 794x1123, so divide by its real height. 1045
         made even a single page sheet report two, which the measure fix exposed. */
      const pages = Math.max(1, Math.ceil(h / 1123));
      setFit((f) => (Math.abs(f.scale - scale) > 0.005 || Math.abs(f.h - h) > 2 || f.pages !== pages) ? { scale, h, pages } : f);
    }
    let raf = requestAnimationFrame(measure);
    window.addEventListener("resize", measure);
    return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", measure); };
  });

  function setItems(next) { setDraft((d) => ({ ...d, items: next })); }
  function toggleItem(productId) {
    setDraft((d) => {
      if (d.items.some((x) => x.productId === productId)) {
        return { ...d, items: d.items.filter((x) => x.productId !== productId) };
      }
      const p = PLM.productsById()[productId];
      if (!p) return d;
      return { ...d, items: [...d.items, { productId: productId, rate: p.rate }] };
    });
  }
  function setRate(productId, rate) {
    setItems(draft.items.map((x) => x.productId === productId ? { ...x, rate: rate } : x));
  }

  const docLabel = "Quick quote" + (draft.customer.trim() ? " for " + draft.customer.trim() : "");
  const fileBase = window.safeName(window.isoDate() + " NGIPL Quotation" + (draft.customer.trim() ? " " + draft.customer.trim() : ""));

  async function onDownloadPdf() {
    if (pdfBusy || !items.length) return;
    const sheet = wrapRef.current ? wrapRef.current.querySelector(".sheet") : null;
    if (!sheet) return;
    setPdfBusy(true);
    try {
      const name = fileBase + ".pdf";
      await sheetToPdf(sheet, name);
      PLM.logPrint("Quick quote PDF: " + (draft.customer.trim() || "unnamed") + " (" + items.length + " item" + (items.length === 1 ? "" : "s") + ")");
    } catch (err) {
      console.error(err);
      window.alert("PDF export failed: " + err.message + "\nUse Print / Save PDF instead.");
    }
    setPdfBusy(false);
  }

  /* One sharp JPG of the whole quote, sized so WhatsApp's photo compression barely touches it.
     Rendered from an off-screen clone at the sheet's true 794px width, so the on-screen
     preview scale never blurs the output. */
  async function onDownloadJpg() {
    if (pdfBusy || !items.length) return;
    const sheet = wrapRef.current ? wrapRef.current.querySelector(".sheet") : null;
    if (!sheet) return;
    setPdfBusy(true);
    try {
      await loadPdfLibs();
      const wrap = document.createElement("div");
      wrap.style.cssText = "position:fixed;left:-10000px;top:0;width:794px;background:#ffffff;";
      const clone = sheet.cloneNode(true);
      clone.style.transform = "none";
      wrap.appendChild(clone);
      document.body.appendChild(wrap);
      try {
        if (document.fonts && document.fonts.ready) { try { await document.fonts.ready; } catch (e) {} }
        const canvas = await window.html2canvas(clone, { scale: 2, useCORS: true, backgroundColor: "#ffffff", logging: false });
        const name = fileBase + ".jpg";
        const how = await window.deliverFile(await window.canvasToBlob(canvas, "image/jpeg", 0.92), name, { title: name });
        if (how !== "cancelled") {
          PLM.logPrint("Quick quote JPG: " + (draft.customer.trim() || "unnamed") + " (" + items.length + " item" + (items.length === 1 ? "" : "s") + ")");
        }
      } finally {
        wrap.remove();
      }
    } catch (err) {
      console.error(err);
      window.alert("Image export failed: " + err.message);
    }
    setPdfBusy(false);
  }

  return (
    <div data-screen-label="Quick Quote">
      <div className="print-controls">
        <div className="toolbar toolbar--tight">
          <Field label="Prepared for">
            <input className="f-input f-input--sm f-input--client" placeholder="Client / hotel name (optional)"
              value={draft.customer} onChange={(e) => setDraft({ ...draft, customer: e.target.value })} />
          </Field>
          <Field label="Letterhead">
            <Seg options={[{ value: "charcoal", label: "Charcoal" }, { value: "minimal", label: "Minimal" }]}
              value={headerStyle} onChange={onHeaderStyle}></Seg>
          </Field>
          <div className="spacer"></div>
          <span className="caption tnum" style={{ whiteSpace: "nowrap" }}>A4 · ≈ {fit.pages} page{fit.pages === 1 ? "" : "s"}</span>
          <Btn variant="ghost" onClick={onDownloadPdf} disabled={pdfBusy || !items.length}><IDownload size={14}></IDownload> {pdfBusy ? "Preparing…" : (window.CAN_SHARE_FILES ? "Share PDF" : "Download PDF")}</Btn>
          <Btn variant="ghost" title="One sharp image of the quote. On a phone this opens the share sheet, so it goes straight into WhatsApp." onClick={onDownloadJpg} disabled={pdfBusy || !items.length}><IDownload size={14}></IDownload> {window.CAN_SHARE_FILES ? "Share JPG" : "Download JPG"}</Btn>
          <Btn className="tb-wide" title="In the print dialog use: Margins: Default · Scale: 100% · Background graphics: ON" disabled={!items.length} onClick={() => {
            PLM.logPrint("Printed quick quote: " + (draft.customer.trim() || "unnamed") + " (" + items.length + " items)");
            window.print();
          }}><IPrinter size={14}></IPrinter> Print</Btn>
        </div>

        <div className="print-opts panel">
          <Btn className="po-add" variant="secondary" size="sm" onClick={() => setPickerOpen(true)}><IPlus size={13}></IPlus> Add items</Btn>
          <span className="caption po-count">{items.length} item{items.length === 1 ? "" : "s"} on the quote</span>
          <Field label="Quote note" className="po-field--note">
            <input className="f-input f-input--sm" value={draft.note}
              onChange={(e) => setDraft({ ...draft, note: e.target.value })} />
          </Field>
          {items.length ? (
            confirmClear ? (
              <span className="po-confirm">
                <span className="caption">Clear the quote?</span>
                <Btn variant="danger" size="sm" onClick={() => { setDraft({ customer: "", note: QQ_DEFAULT_NOTE, items: [] }); setConfirmClear(false); toast("Quick quote cleared"); }}>Clear</Btn>
                <Btn variant="ghost" size="sm" onClick={() => setConfirmClear(false)}>Keep</Btn>
              </span>
            ) : (
              <Btn variant="ghost" size="sm" className="po-clear" onClick={() => setConfirmClear(true)}>Clear</Btn>
            )
          ) : null}
        </div>

        {sorted.length ? (
          <div className="panel panel--strong plm-table-wrap qq-rows" style={{ marginBottom: 16 }}>
            <table className="plm-table">
              <thead>
                <tr>
                  <th className="col-no">#</th>
                  <th>Item</th>
                  <th className="num col-master" style={{ width: 90 }}>Master ₹</th>
                  <th className="num" style={{ width: 100 }}>Quote ₹</th>
                  <th style={{ width: 70 }}></th>
                  <th className="col-unit" style={{ width: 80 }}>Unit</th>
                  <th className="num col-pack" style={{ width: 90 }}>Pack size</th>
                  <th className="num col-gst" style={{ width: 64 }}>GST</th>
                  <th style={{ width: 56 }}></th>
                </tr>
              </thead>
              <tbody>
                {sorted.map((it) => {
                  const p = pb[it.productId];
                  const delta = PLM.deltaPct(it.rate, p.rate);
                  return (
                    <tr className="item-row" key={it.productId}>
                      <td className="col-no">{nm[it.productId] || "-"}</td>
                      <td>
                        <div>{p.name}</div>
                        {p.note ? <div className="item-note">{p.note}</div> : null}
                        <div className="row-meta">#{nm[it.productId] || "-"} · Master ₹{PLM.fmtRate(p.rate)} · {p.unit} · {PLM.fmtPack(p.packSize)} · GST {PLM.fmtGst(p.gst)}</div>
                      </td>
                      <td className="num tnum col-master" style={{ color: "var(--text-faint)" }}>₹{PLM.fmtRate(p.rate)}</td>
                      <td className="num rate"><RateCell value={it.rate} onCommit={(r) => setRate(it.productId, r)}></RateCell></td>
                      <td>{delta ? <span className={"chip" + (it.rate > p.rate ? "" : " chip--warn")}>{delta}</span> : null}</td>
                      <td className="col-unit">{p.unit}</td>
                      <td className="num col-pack">{PLM.fmtPack(p.packSize)}</td>
                      <td className="num col-gst">{PLM.fmtGst(p.gst)}</td>
                      <td>
                        <span className="row-actions">
                          <IconBtn title="Remove from quote" onClick={() => toggleItem(it.productId)}><IX size={14}></IX></IconBtn>
                        </span>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        ) : null}
        <div className="caption" style={{ marginBottom: 16 }}>
          The quote itself is never saved to the shared database. The draft stays on this device until cleared, and rates edited here change only this quote, never the master list. Downloading or printing does add one line to Revision history so everyone can see what went out.
        </div>
      </div>

      {items.length ? (
        <div className="print-desk" ref={deskRef}>
          <div className="desk-doclabel">{docLabel}</div>
          <div className="sheet-scale" ref={wrapRef}
            style={{ transform: "scale(" + fit.scale + ")", width: 794 * fit.scale, height: fit.h ? fit.h * fit.scale : "auto" }}>
            <PriceSheet quick={quick} headerStyle={headerStyle}></PriceSheet>
          </div>
        </div>
      ) : (
        <div className="panel print-controls" style={{ padding: 40, textAlign: "center" }}>
          <div className="caption">No items on the quote yet. Press <strong>Add items</strong>, pick the products to show, then adjust any rate before sending it out.</div>
        </div>
      )}

      {pickerOpen ? <QQPickerDialog selectedIds={items.map((x) => x.productId)} onToggle={toggleItem} onClose={() => setPickerOpen(false)}></QQPickerDialog> : null}
    </div>
  );
}

function QQPickerDialog({ selectedIds, onToggle, onClose }) {
  const state = PLM.useStore();
  const [q, setQ] = useState("");
  const nm = PLM.numberMap();
  const query = q.trim().toLowerCase();
  const sel = {};
  selectedIds.forEach((id) => { sel[id] = true; });
  const bands = PLM.groupedProducts()
    .map((b) => ({
      cat: b.cat,
      items: b.groups.flatMap((g) => g.items).filter((p) => !query || p.name.toLowerCase().includes(query) || (p.note || "").toLowerCase().includes(query)),
    }))
    .filter((b) => b.items.length);
  return (
    <Dialog title="Add items to the quote" onClose={onClose} width={680}
      footer={
        <React.Fragment>
          <span className="caption" style={{ marginRight: "auto" }}>{selectedIds.length} selected</span>
          <Btn size="sm" onClick={onClose}>Done</Btn>
        </React.Fragment>
      }>
      <div className="f-stack">
        <div className="search-box">
          <ISearch size={15}></ISearch>
          <input className="f-input" placeholder="Search items…" value={q} onChange={(e) => setQ(e.target.value)} autoFocus />
        </div>
        <div className="panel" style={{ maxHeight: 380, overflow: "auto" }}>
          <table className="plm-table">
            <tbody>
              {bands.map((band) => (
                <React.Fragment key={band.cat.id}>
                  <tr className="cat-band"><td colSpan={4}><span className="band-cell"><CatIcon catId={band.cat.id} size={18}></CatIcon><span>{band.cat.name}</span></span></td></tr>
                  {band.items.map((p) => (
                    <tr className="item-row" key={p.id} style={{ cursor: "pointer" }} onClick={() => onToggle(p.id)}>
                      <td style={{ width: 36, textAlign: "center" }}>
                        <input type="checkbox" checked={!!sel[p.id]} readOnly style={{ pointerEvents: "none" }} />
                      </td>
                      <td className="col-no">{nm[p.id]}</td>
                      <td>
                        <div>{p.name}</div>
                        {p.note ? <div className="item-note">{p.note}</div> : null}
                      </td>
                      <td className="num tnum" style={{ width: 100, color: "var(--text-faint)" }}>₹{PLM.fmtRate(p.rate)}</td>
                    </tr>
                  ))}
                </React.Fragment>
              ))}
              {!bands.length ? <tr><td style={{ padding: 20 }} className="caption">No items match.</td></tr> : null}
            </tbody>
          </table>
        </div>
      </div>
    </Dialog>
  );
}

Object.assign(window, { QuickQuoteView });
