// commercial-proposals.jsx — Комерційні пропозиції (Продажі).
// Структурована форма → стандартний текст КП (як «Хаб Ветеран») → друк на бланку
// (LetterPrintDoc). Зберігається як реєстр (commercial-proposals); при створенні
// додається запис у Журнал вихідної кореспонденції (window.logOutgoing).

const CP_STATUS = {
  draft:    { label: "Чернетка",  tone: "neutral" },
  sent:     { label: "Надіслано", tone: "blue" },
  accepted: { label: "Прийнято",  tone: "green" },
  declined: { label: "Відхилено", tone: "red" },
};
const CP_MONTHS_WORD = ["", "один", "два", "три", "чотири", "п'ять", "шість", "сім", "вісім", "дев'ять", "десять", "одинадцять", "дванадцять"];

function cpDots(iso) { return iso ? (window.dateDots ? window.dateDots(iso) : iso) : ""; }

// Клікабельний статус-тег: натискаєш — обираєш новий статус зі списку.
// Меню рендериться у портал (fixed), щоб його не обрізав `overflow:hidden`
// картки (.contract-card) — інакше список статусів кліпається і не клікається.
function CpStatusTag({ value, editable, onChange }) {
  const [open, setOpen] = React.useState(false);
  const [pos, setPos] = React.useState(null);
  const btnRef = React.useRef(null);
  const menuRef = React.useRef(null);
  const st = CP_STATUS[value] || CP_STATUS.draft;

  const place = React.useCallback(() => {
    const b = btnRef.current;
    if (!b) return;
    const r = b.getBoundingClientRect();
    setPos({ top: r.bottom + 4, right: Math.max(8, window.innerWidth - r.right) });
  }, []);

  React.useEffect(() => {
    if (!open) return;
    place();
    const onDoc = (e) => {
      if (btnRef.current && btnRef.current.contains(e.target)) return;
      if (menuRef.current && menuRef.current.contains(e.target)) return;
      setOpen(false);
    };
    const onScroll = () => setOpen(false);
    document.addEventListener("mousedown", onDoc);
    window.addEventListener("scroll", onScroll, true);
    window.addEventListener("resize", onScroll);
    return () => {
      document.removeEventListener("mousedown", onDoc);
      window.removeEventListener("scroll", onScroll, true);
      window.removeEventListener("resize", onScroll);
    };
  }, [open, place]);

  if (!editable) return <span className={`status-tag tone-${st.tone}`}>{st.label}</span>;

  const menu = open && pos ? ReactDOM.createPortal(
    <div
      ref={menuRef}
      className="cp-status-menu cp-status-menu--fixed"
      style={{ position: "fixed", top: pos.top, right: pos.right }}
    >
      {Object.keys(CP_STATUS).map(k => {
        const o = CP_STATUS[k];
        return (
          <button
            key={k}
            type="button"
            className={`cp-status-menu-item ${k === value ? "is-active" : ""}`}
            onClick={() => { setOpen(false); if (k !== value) onChange(k); }}
          >
            <span className={`cp-status-dot tone-${o.tone}`}></span>{o.label}
          </button>
        );
      })}
    </div>,
    document.body
  ) : null;

  return (
    <div className="cp-status-wrap" style={{ position: "relative" }}>
      <button
        ref={btnRef}
        type="button"
        className={`status-tag tone-${st.tone} cp-status-btn`}
        title="Змінити статус"
        onClick={() => setOpen(o => !o)}
      >
        {st.label} <span style={{ opacity: .6, fontSize: 10 }}>▾</span>
      </button>
      {menu}
    </div>
  );
}

// Локальне поле форми (як в edrpou-page/orders-page) — не покладаємось на глобал.
function OWField({ label, children, wide }) {
  return (
    <label className={`ow-field ${wide ? "ow-wide" : ""}`}>
      <span className="ow-label">{label}</span>
      {children}
    </label>
  );
}

// Будує абзаци тіла КП зі структурованих полів (формулювання за зразком «Хаб Ветеран»).
function buildProposalBody(p, co) {
  const shortName = (co && co.shortName) || "ТОВ «УКРБУДПРОЄКТ»";
  const sum = Number(p.total) || 0;
  const withVat = p.vatMode !== "without";
  const vat = withVat ? Math.round(sum / 6 * 100) / 100 : 0;  // ПДВ 20% у т.ч. = сума/6
  const fm = window.formatMoney || ((n) => String(n));
  const words = window.moneyInWords ? window.moneyInWords(sum) : "";
  const ref = (p.inNo || p.inDate)
    ? `У відповідь на Ваше звернення (лист${p.inDate ? " від " + cpDots(p.inDate) : ""}${p.inNo ? " № " + p.inNo : ""}) `
    : "";
  const mN = Number(p.termMonths) || 0;
  const mWord = (mN >= 1 && mN <= 12) ? CP_MONTHS_WORD[mN] : "";
  const out = [];
  out.push(`${ref}${shortName} надає свою пропозицію на роботи з розробки проєктної документації на ${p.subject || "[опис об'єкта та робіт]"}${p.objectAddress ? ", розташованих за адресою: " + p.objectAddress : ""} (далі — Роботи) за наступними цінами:`);
  out.push(`Загальна вартість робіт: ${fm(sum)} грн${words ? " (" + words + ")" : ""}${withVat ? ", у тому числі ПДВ 20% — " + fm(vat) + " грн" : " (без ПДВ)"}.`);
  out.push(`Терміни виконання робіт: ${mN || "[__]"}${mWord ? " (" + mWord + ")" : ""} календарні місяці з моменту підписання договору.`);
  out.push("Терміни виконання Робіт можуть бути подовжені у разі ненадання (несвоєчасного надання) Замовником вихідних даних, необхідних для розробки проєктної документації.");
  if (p.expertiseSeparate) out.push("Проходження експертизи проєктної документації здійснюється та оплачується Замовником окремо і у вартість Робіт не входить.");
  return out;
}

// Зібрати об'єкт листа для LetterPrintDoc.
function proposalLetter(p, co) {
  return {
    outNo: p.number || "", outDate: cpDots(p.date),
    inNo: p.inNo || "", inDate: cpDots(p.inDate),
    addressee: p.addressee || [],
    salutation: p.salutation || "",
    title: "",
    body: (p.body && p.body.length) ? p.body : buildProposalBody(p, co),
    attachments: [],
  };
}

// Приклад «Хаб Ветеран» — як шаблон-зразок для нової КП.
function cpVeteranSample() {
  return {
    inNo: "01-07/116", inDate: "2026-06-19",
    addressee: ["В.о. директора", "КУ «Сервісний офіс «Хаб Ветеран»", "Ірині АХРАМЄЄВІЙ"],
    salutation: "Шановна пані Ірино!",
    subject: "капітальний ремонт нежитлових приміщень першого поверху № 502 загальною площею 237,4 кв.м, для облаштування безбар'єрної адаптивної спортивної зали",
    objectAddress: "м. Одеса, вул. Маріупольська, 4",
    total: 778235.37, vatMode: "with", termMonths: 3, expertiseSeparate: true,
  };
}

function CommercialProposalForm({ proposal, onClose, onSaved }) {
  const co = window.COMPANY || {};
  const clients = window.DATA.CLIENTS || [];
  const SYS = window.SYS_DATE || "2026-06-29";
  const [busy, setBusy] = React.useState(false);
  const [estBuilder, setEstBuilder] = React.useState(false);
  const [estimate, setEstimate] = React.useState(() => (proposal && proposal.estimate) || null);
  const [f, setF] = React.useState(() => ({
    id: proposal && proposal.id || null,
    number: (proposal && proposal.number) || (window.nextProposalNumber ? window.nextProposalNumber() : ""),
    date: (proposal && proposal.date) || SYS,
    inNo: (proposal && proposal.inNo) || "", inDate: (proposal && proposal.inDate) || "",
    client: (proposal && proposal.client) || "",
    addresseeText: ((proposal && proposal.addressee) || []).join("\n"),
    salutation: (proposal && proposal.salutation) || "",
    subject: (proposal && proposal.subject) || "",
    objectAddress: (proposal && proposal.objectAddress) || "",
    total: (proposal && proposal.total) || "",
    vatMode: (proposal && proposal.vatMode) || "with",
    termMonths: (proposal && proposal.termMonths) || 3,
    expertiseSeparate: proposal ? !!proposal.expertiseSeparate : true,
    status: (proposal && proposal.status) || "draft",
  }));
  const set = (k, v) => setF(p => ({ ...p, [k]: v }));
  React.useEffect(() => {
    const onKey = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const applySample = () => setF(p => ({ ...p, ...cpVeteranSample(), addresseeText: cpVeteranSample().addressee.join("\n") }));
  const pickClient = (id) => {
    const c = clients.find(x => x.id === id);
    setF(p => ({ ...p, client: id, addresseeText: p.addresseeText || (c ? c.name : "") }));
  };

  const addressee = f.addresseeText.split("\n").map(s => s.trim()).filter(Boolean);
  const valid = f.number.trim() && Number(f.total) > 0 && f.subject.trim() && addressee.length > 0;

  const toRecord = () => {
    const rec = {
      id: f.id || undefined,
      number: f.number.trim(), date: f.date, inNo: f.inNo.trim(), inDate: f.inDate || null,
      client: f.client || null, addressee, salutation: f.salutation.trim(),
      subject: f.subject.trim(), objectAddress: f.objectAddress.trim(),
      total: Number(f.total) || 0, vatMode: f.vatMode, termMonths: Number(f.termMonths) || null,
      expertiseSeparate: f.expertiseSeparate, status: f.status,
      estimate: estimate || null,
    };
    rec.body = buildProposalBody(rec, co);  // снапшот тексту для друку/реоупену
    return rec;
  };

  const save = async () => {
    if (!valid || busy) return;
    setBusy(true);
    const rec = toRecord();
    try {
      const saved = await window.API.save("commercial-proposals", f.id || null, rec);
      const isNew = !f.id;
      // Лог у журнал вихідної кореспонденції — лише для нових КП.
      if (isNew && window.logOutgoing) {
        const clientName = (clients.find(x => x.id === f.client) || {}).short;
        await window.logOutgoing({
          docNo: rec.number, docDate: rec.date,
          counterparty: addressee.join(", ") || clientName || "",
          summary: "Комерційна пропозиція" + (rec.subject ? " — " + rec.subject : ""),
          regIndex: rec.number,
        });
      }
      onSaved && onSaved(saved || rec);
      onClose();
    } catch (e) {
      console.error("[ERP] save proposal failed:", e);
      alert("Не вдалося зберегти комерційну пропозицію на сервері.");
    } finally { setBusy(false); }
  };

  return (
    <div className="ow-root">
      <div className="ow-backdrop" onClick={onClose}></div>
      <div className="ow-modal" style={{ width: 720 }}>
        <div className="ow-head">
          <div>
            <div className="ow-title">{f.id ? "Редагувати комерційну пропозицію" : "Нова комерційна пропозиція"}</div>
            <div className="ow-sub">№ {f.number || "—"} · {cpDots(f.date)}</div>
          </div>
          <button className="ow-x" onClick={onClose}><window.Ico name="plus" style={{ transform: "rotate(45deg)" }} /></button>
        </div>
        <div className="ow-body">
          {!f.id && (
            <div className="hint-box" style={{ marginBottom: 12, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }}>
              <span>Заповніть поля — текст пропозиції збудується автоматично. Можна підставити зразок.</span>
              <button className="btn" onClick={applySample}>Підставити зразок «Хаб Ветеран»</button>
            </div>
          )}
          <div className="ow-grid">
            <OWField label="Замовник (зі списку, опц.)" wide>
              <select value={f.client} onChange={e => pickClient(e.target.value)}>
                <option value="">— не обрано —</option>
                {clients.map(c => <option key={c.id} value={c.id}>{c.short} · {c.edrpou}</option>)}
              </select>
            </OWField>
            <OWField label="Адресат (кому) — кожен рядок з нового рядка" wide>
              <textarea rows={3} value={f.addresseeText} onChange={e => set("addresseeText", e.target.value)} placeholder={"В.о. директора\nКУ «…»\nІмені ПРІЗВИЩЕ"} />
            </OWField>
            <OWField label="Звертання" wide><input value={f.salutation} onChange={e => set("salutation", e.target.value)} placeholder="напр. Шановна пані Ірино!" /></OWField>
            <OWField label="№ вих. (наш)"><input value={f.number} onChange={e => set("number", e.target.value)} /></OWField>
            <OWField label="Дата КП"><input type="date" value={f.date} onChange={e => set("date", e.target.value)} /></OWField>
            <OWField label="№ вхідного запиту (на що відповідь)"><input value={f.inNo} onChange={e => set("inNo", e.target.value)} placeholder="напр. 01-07/116" /></OWField>
            <OWField label="Дата вхідного запиту"><input type="date" value={f.inDate} onChange={e => set("inDate", e.target.value)} /></OWField>
            <OWField label="Опис об'єкта / робіт" wide><textarea rows={2} value={f.subject} onChange={e => set("subject", e.target.value)} placeholder="напр. капітальний ремонт нежитлових приміщень… загальною площею … кв.м" /></OWField>
            <OWField label="Адреса об'єкта" wide><input value={f.objectAddress} onChange={e => set("objectAddress", e.target.value)} placeholder="напр. м. Одеса, вул. …" /></OWField>
            <OWField label="Загальна вартість, грн"><input type="number" step="0.01" value={f.total} onChange={e => set("total", e.target.value)} placeholder="778235.37" disabled={!!estimate} title={estimate ? "Вартість береться з кошторису" : ""} /></OWField>
            <OWField label="ПДВ">
              <select value={f.vatMode} onChange={e => set("vatMode", e.target.value)}>
                <option value="with">У т.ч. ПДВ 20%</option>
                <option value="without">Без ПДВ</option>
              </select>
            </OWField>
            <OWField label="Строк виконання, міс"><input type="number" value={f.termMonths} onChange={e => set("termMonths", e.target.value)} /></OWField>
            <OWField label="Статус">
              <select value={f.status} onChange={e => set("status", e.target.value)}>
                {Object.keys(CP_STATUS).map(k => <option key={k} value={k}>{CP_STATUS[k].label}</option>)}
              </select>
            </OWField>
            <OWField label="Експертиза" wide>
              <label style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13 }}>
                <input type="checkbox" checked={f.expertiseSeparate} onChange={e => set("expertiseSeparate", e.target.checked)} /> Експертиза оплачується Замовником окремо (не входить у вартість)
              </label>
            </OWField>
            <OWField label="Кошторис" wide>
              <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
                <button type="button" className="btn" onClick={() => setEstBuilder(true)}>
                  <window.Ico name="pencil" /> {estimate ? "Редагувати кошторис" : "Скласти кошторис"}
                </button>
                {estimate
                  ? <span style={{ fontSize: 12.5, color: "var(--ink-2, var(--ink))" }}>
                      ✓ форми 1-П/2-П/3-П · разом <b>{window.formatMoney(window.estimateTotals ? window.estimateTotals(estimate).grand : (estimate.total || 0))} ₴</b>
                    </span>
                  : <span style={{ fontSize: 12, color: "var(--ink-3)" }}>необов'язково — якщо додати, вартість КП рахується з кошторису</span>}
                {estimate && <button type="button" className="btn btn-sm" title="Прибрати кошторис" onClick={() => { setEstimate(null); }}>✕ прибрати</button>}
              </div>
            </OWField>
          </div>
          <div className="ow-foot">
            <span className="ow-foot-hint">{f.id ? "Зміни збережуться у реєстрі." : "Створиться запис у реєстрі + у Журналі вихідної кореспонденції."}</span>
            <button className="btn" onClick={onClose}>Скасувати</button>
            <button className="btn btn-primary" disabled={!valid || busy} onClick={save}>{busy ? "Збереження…" : (f.id ? "Зберегти" : "Створити")}</button>
          </div>
        </div>
      </div>
      {estBuilder && window.EstimateBuilder && (
        <window.EstimateBuilder
          initial={estimate}
          seed={{
            objectName: f.subject, objectAddress: f.objectAddress,
            customer: (clients.find(x => x.id === f.client) || {}).name || addressee[0] || "",
            proposalNumber: f.number, proposalDate: cpDots(f.date),
          }}
          onClose={() => setEstBuilder(false)}
          onSave={(est, grand) => { setEstimate(est); setF(p => ({ ...p, total: grand })); }}
        />
      )}
    </div>
  );
}

function CommercialProposalsPage({ role }) {
  const co = window.COMPANY || {};
  const [rows, setRows] = React.useState([]);
  const [filter, setFilter] = React.useState("all");
  const [form, setForm] = React.useState(null);     // null | {} | proposal
  const [printP, setPrintP] = React.useState(null);
  const [printEst, setPrintEst] = React.useState(null);
  const [contractCP, setContractCP] = React.useState(null); // КП, з якої створюємо договір
  const canEdit = role === "director" || role === "accountant" || role === "sales" || role === "deputy";

  const reload = React.useCallback(() => {
    if (!(window.API && window.API.list)) return;
    window.API.list("commercial-proposals", {})
      .then(r => setRows((r || []).slice().sort((a, b) => (b.date || "").localeCompare(a.date || ""))))
      .catch(() => {});
  }, []);
  React.useEffect(() => { reload(); }, [reload]);

  const shown = filter === "all" ? rows : rows.filter(p => p.status === filter);
  const totalSum = rows.reduce((s, p) => s + (p.total || 0), 0);
  // Розподіл кількості і сум по статусах.
  const breakdown = React.useMemo(() => {
    const acc = {};
    Object.keys(CP_STATUS).forEach(k => { acc[k] = { count: 0, sum: 0 }; });
    rows.forEach(p => { const k = CP_STATUS[p.status] ? p.status : "draft"; acc[k].count++; acc[k].sum += (p.total || 0); });
    return acc;
  }, [rows]);

  const changeStatus = (p, next) => {
    // Оптимістично оновлюємо локально, потім патчимо на сервері.
    setRows(rs => rs.map(x => x.id === p.id ? { ...x, status: next } : x));
    if (window.API && window.API.patch) {
      window.API.patch("/commercial-proposals/" + p.id, { status: next }).catch(reload);
    }
  };

  const remove = (id) => {
    if (!window.confirm("Видалити комерційну пропозицію?")) return;
    window.API.del("/commercial-proposals/" + id).then(reload).catch(() => {});
  };
  const duplicate = (p) => {
    const SYS = window.SYS_DATE || "2026-06-29";
    setForm({ ...p, id: undefined, number: (window.nextProposalNumber ? window.nextProposalNumber() : ""), date: SYS, status: "draft" });
  };

  return (
    <div className="page">
      <div className="page-head">
        <h1 className="page-h1">Комерційні пропозиції</h1>
        <div className="page-sub">
          <span>{rows.length} {window.plural(rows.length, "пропозиція", "пропозиції", "пропозицій")}</span>
          <span className="dot"></span>
          <span>на суму <b style={{ color: "var(--ink)" }}>{window.formatMoney(totalSum)} ₴</b></span>
        </div>
      </div>

      <div className="toolbar">
        <div className="filter-pill" role="tablist">
          <button className={`filter-pill-item ${filter === "all" ? "is-active" : ""}`} onClick={() => setFilter("all")}>Усі</button>
          {Object.keys(CP_STATUS).map(k => (
            <button key={k} className={`filter-pill-item ${filter === k ? "is-active" : ""}`} onClick={() => setFilter(k)}>{CP_STATUS[k].label}</button>
          ))}
        </div>
        {canEdit && <button className="btn btn-primary" style={{ marginLeft: "auto" }} onClick={() => setForm({})}><window.Icon.Plus /> Нова пропозиція</button>}
      </div>

      <div className="cp-stats">
        {Object.keys(CP_STATUS).map(k => {
          const o = CP_STATUS[k], b = breakdown[k] || { count: 0, sum: 0 };
          return (
            <button
              key={k}
              type="button"
              className={`cp-stat tone-${o.tone} ${filter === k ? "is-active" : ""}`}
              onClick={() => setFilter(f => f === k ? "all" : k)}
            >
              <span className="cp-stat-label"><span className={`cp-status-dot tone-${o.tone}`}></span>{o.label}</span>
              <span className="cp-stat-sum">{window.formatMoney(b.sum)} ₴</span>
              <span className="cp-stat-count">{b.count} {window.plural(b.count, "пропозиція", "пропозиції", "пропозицій")}</span>
            </button>
          );
        })}
      </div>

      <div className="contract-stack">
        {shown.length === 0 && <div className="hint-box">Пропозицій ще немає. Натисніть «Нова пропозиція».</div>}
        {shown.map(p => {
          return (
            <div key={p.id} className="contract-card" style={{ cursor: "default" }}>
              <div className="contract-card-head" style={{ cursor: "default" }}>
                <div className="contract-num">
                  <div className="contract-num-val">№ {p.number}</div>
                  <div className="contract-num-date">{cpDots(p.date)}</div>
                </div>
                <div className="contract-main">
                  <div className="contract-name">{(p.addressee || [])[0] || "Адресат"} <span style={{ fontWeight: 400, color: "var(--ink-3)" }}>· {(p.addressee || [])[1] || ""}</span></div>
                  <div className="contract-meta">
                    <span style={{ maxWidth: 460, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", display: "inline-block" }}>{p.subject}</span>
                  </div>
                </div>
                <div className="contract-amount">
                  <div className="contract-amount-val">{window.formatMoney(p.total)} <span style={{ color: "var(--ink-3)", fontWeight: 500, fontSize: 13 }}>₴</span></div>
                  <div className="contract-amount-paid">{p.vatMode === "without" ? "без ПДВ" : "у т.ч. ПДВ"}</div>
                </div>
                <CpStatusTag value={p.status} editable={canEdit} onChange={(next) => changeStatus(p, next)} />
                <div style={{ display: "flex", gap: 6, marginLeft: 10 }}>
                  <button className="btn btn-sm" title="Друк / PDF" onClick={() => setPrintP(p)}><window.Ico name="download" /> Друк</button>
                  {p.estimate && <button className="btn btn-sm" title="Друк кошторису (Додаток № 4)" onClick={() => setPrintEst(p)}><window.Ico name="download" /> Кошторис</button>}
                  {canEdit && window.ContractWizard && <button className="btn btn-sm" title="Створити договір на основі цієї КП" onClick={() => setContractCP(p)}><window.Ico name="file" /> Договір</button>}
                  {canEdit && <button className="btn btn-sm" title="Редагувати" onClick={() => setForm(p)}>✎</button>}
                  {canEdit && <button className="btn btn-sm" title="Дублювати як шаблон" onClick={() => duplicate(p)}>⧉</button>}
                  {canEdit && <button className="btn btn-sm" title="Видалити" onClick={() => remove(p.id)}>✕</button>}
                </div>
              </div>
            </div>
          );
        })}
      </div>

      {contractCP && window.ContractWizard && (
        <window.ContractWizard
          presetCP={contractCP}
          onClose={(rec) => {
            const cp = contractCP;
            setContractCP(null);
            if (rec) {
              // КП реалізовано договором → статус «Прийнято» + перехід у реєстр договорів.
              if (cp.status !== "accepted") changeStatus(cp, "accepted");
              if (window.__setPage) window.__setPage("contracts");
            }
          }}
        />
      )}
      {form && <CommercialProposalForm proposal={form.id ? form : (Object.keys(form).length ? form : null)} onClose={() => setForm(null)} onSaved={reload} />}
      {printP && window.LetterPrintDoc && <window.LetterPrintDoc letter={proposalLetter(printP, co)} onClose={() => setPrintP(null)} />}
      {printEst && window.EstimatePrintDoc && (
        <window.EstimatePrintDoc
          est={printEst.estimate}
          context="proposal"
          meta={{ customer: (printEst.addressee || [])[0] || "", objectName: printEst.subject, objectAddress: printEst.objectAddress, proposalNumber: printEst.number, proposalDate: cpDots(printEst.date) }}
          onClose={() => setPrintEst(null)} />
      )}
    </div>
  );
}

window.CommercialProposalsPage = CommercialProposalsPage;
window.buildProposalBody = buildProposalBody;
