// estimate-builder.jsx — Кошторис (Додаток № 4) до КП і до Договору.
// Форми за Настановою (наказ Мінрегіону № 281 від 01.11.2021). Нумерація наскрізна й динамічна
// (обстеження можна вимкнути — тоді решта перенумеровується):
//   • Кошторис № 1 — Зведений (форма 1-П)                    — авто-зведення
//   • Технічне обстеження будівель і споруд (3-П)            — вишукувальні; не потрібне для нового будівництва
//   • Проєктні роботи (3-П)                                  — посади × люд-дн × показник
//   • Реєстрація в ЄДЕССБ (3-П)
//   • Експертиза (2-П)                                       — ручна база + % + ПДВ (автоінтерполяція — пізніше)
//   • Розрахунок показника вартості 1 люд-дня (аркуш 6)
// Кошторис живе полем `estimate` на записі КП; при друці КП і Договору рендериться як Додаток № 4.
// Показник — глобальний (window.ESTIMATE_RATE), редагується тут і зберігається через PUT /estimate-rate.

// ─────────────────────────── Обчислення показника (люд-день) ───────────────────────────
function esN(v, d) { const n = Number(v); return isFinite(n) ? n : (d || 0); }
function esRound2(n) { return Math.round((Number(n) || 0) * 100) / 100; }
function esRnd(n, d) { const f = Math.pow(10, d); return Math.round((Number(n) || 0) * f) / f; }

// Повний ланцюг розрахунку показника з аркуша 6 (звірено з кошторисом О-1: 1780×2,2216=3954,448).
window.estimateRate = function (over) {
  const r = Object.assign({}, window.ESTIMATE_RATE || {}, over || {});
  const hoursPerMonth = esN(r.hoursPerMonth, 171.75);   // 1.1
  const hoursPerDay = esN(r.hoursPerDay, 8);            // 1.2
  const baseIndicator = esN(r.baseIndicator, 1780);      // 1.4
  const monthlyWageBase38 = esN(r.monthlyWageBase38, 10628.39); // 1.5
  const rankCoef7 = esN(r.rankCoef7, 2.075);             // 1.7
  const rankCoef38 = esN(r.rankCoef38, 1.308);           // 1.8
  const esvPct = esN(r.esvPct, 22);                      // 1.13
  const currentWage38 = esN(r.currentWage38, 34748);     // 3.1
  // Методика округлює кожен нумерований рядок до показаної точності і далі рахує
  // від округленого значення (звірено з кошторисом О-1: 1780×2,2216=3954,448).
  const daysPerMonth = hoursPerDay ? esRnd(hoursPerMonth / hoursPerDay, 4) : 0;      // 1.3
  const dailyWageBase38 = daysPerMonth ? esRnd(monthlyWageBase38 / daysPerMonth, 4) : 0; // 1.6
  const rankRatio = rankCoef38 ? esRnd(rankCoef7 / rankCoef38, 4) : 0;               // 1.9
  const dailyWage7 = esRnd(dailyWageBase38 * rankRatio, 4);                          // 1.10
  const shareWage = baseIndicator ? esRnd(dailyWage7 / baseIndicator, 4) : 0;        // 1.11
  const shareWageWithEsv = esRnd(shareWage * (1 + esvPct / 100), 4);                 // 1.14
  const shareOther = esRnd(1 - shareWageWithEsv, 4);                                 // 2.1
  const currentWage7 = esRound2(currentWage38 * rankRatio);                          // 3.2
  const coefWageChange = monthlyWageBase38 ? esRnd(currentWage38 / monthlyWageBase38, 5) : 0; // 3.3
  const coefContract = esRnd(shareWageWithEsv * coefWageChange + shareOther, 4);     // 3.4
  const manDay = esRnd(baseIndicator * coefContract, 3);                             // 4
  return {
    year: r.year, hoursPerMonth, hoursPerDay, baseIndicator, monthlyWageBase38,
    rankCoef7, rankCoef38, esvPct, currentWage38,
    daysPerMonth, dailyWageBase38, rankRatio, dailyWage7,
    shareWage, shareWagePct: shareWage * 100, shareWageWithEsv, shareOther,
    currentWage7, coefWageChange, coefContract, manDay,
  };
};
// Готовий об'єкт для збереження в ESTIMATE_RATE (входи + результат).
window.estimateRatePayload = function (over) {
  const c = window.estimateRate(over);
  return {
    year: c.year, hoursPerMonth: c.hoursPerMonth, hoursPerDay: c.hoursPerDay,
    baseIndicator: c.baseIndicator, monthlyWageBase38: c.monthlyWageBase38,
    rankCoef7: c.rankCoef7, rankCoef38: c.rankCoef38, esvPct: c.esvPct,
    currentWage38: c.currentWage38, manDay: c.manDay,
  };
};
window.estimateManDay = function () { return window.estimateRate().manDay; };

// ─────────────────────────── Підсумки кошторису ───────────────────────────
window.estimateTotals = function (est, manDayOverride) {
  est = est || {};
  const manDay = manDayOverride != null ? manDayOverride : esN(est.manDayRate, window.estimateManDay());
  const sumRows = (rows) => (rows || []).reduce((s, r) => s + esN(r.count, 1) * esN(r.days) * manDay, 0);
  const survey = est.survey || {};
  // Обстеження показуємо лише коли блок присутній (нові кошториси) і не вимкнений вручну.
  // Старі збережені кошториси без цього блока лишаються без порожнього аркуша.
  const surveyEnabled = est.survey != null && survey.enabled !== false;
  const surveyExact = surveyEnabled ? sumRows(survey.rows) : 0;
  const projectExact = sumRows(est.project && est.project.rows);
  const registrationExact = sumRows(est.registration && est.registration.rows);
  const ex = est.expertise || {};
  const expEnabled = ex.enabled !== false;
  const vatPct = esN(ex.vatPct, 20);
  const expNoVat = expEnabled ? esN(ex.sumNoVat) : 0;
  const expVat = esRound2(expNoVat * vatPct / 100);
  const expExact = expNoVat * (1 + vatPct / 100);
  const expTotal = esRound2(expExact);
  // ПДВ на проєктні роботи й реєстрацію нараховуємо, лише якщо виконавець — платник ПДВ (ТОВ).
  // ФОП на спрощеній системі (напр. зразок «Їдальня О-1») працює без ПДВ.
  const worksVat = est.execEntity === "tov";
  const worksVatPct = worksVat ? esN(est.worksVatPct, 20) : 0;
  const surveyVat = esRound2(surveyExact * worksVatPct / 100);
  const projectVat = esRound2(projectExact * worksVatPct / 100);
  const registrationVat = esRound2(registrationExact * worksVatPct / 100);
  const surveyTotal = esRound2(surveyExact + surveyVat);
  const projectTotal = esRound2(projectExact + projectVat);
  const registrationTotal = esRound2(registrationExact + registrationVat);
  const worksNet = surveyExact + projectExact + registrationExact;
  const worksVatSum = esRound2(surveyVat + projectVat + registrationVat);
  const grand = esRound2(surveyTotal + projectTotal + registrationTotal + expTotal);
  // Наскрізна нумерація кошторисів: № 1 — зведений, далі за складом (обстеження перед проєктними).
  let seq = 1;
  const num = {};
  if (surveyEnabled) num.survey = ++seq;
  num.project = ++seq;
  num.registration = ++seq;
  if (expEnabled) num.expertise = ++seq;
  return {
    manDay, expEnabled, vatPct, surveyEnabled, num,
    surveyExact, projectExact, registrationExact, surveyTotal, projectTotal, registrationTotal,
    expNoVat, expVat, expExact, expTotal, grand,
    worksVat, worksVatPct, surveyVat, projectVat, registrationVat, worksNet, worksVatSum,
    // Зведений (1-П): вишукувальні (обстеження) / проєктні / додаткові / всього — з точних
    // (нерозкруглених) сум, без ПДВ на роботи (ПДВ показуємо окремим рядком у зведеному).
    summary: {
      vyshukuvalnyh: surveyExact,
      proektnih: projectExact,
      dodatkovih: registrationExact + expExact,
      vsogo: surveyExact + projectExact + registrationExact + expExact,
    },
  };
};

// Технічне обстеження не потрібне лише для нового будівництва — визначаємо за назвою об'єкта
// («Нове будівництво…», «Нового будівництва…»). Реконструкція/капремонт/тех.переоснащення потребують.
window.isNewConstruction = function (name) {
  return /нов\S*\s+будівництв/i.test(String(name || ""));
};

// Стандартний склад команди (посади) — стартові рядки нового кошторису.
window.defaultEstimate = function (seed) {
  seed = seed || {};
  const pos = (p, days) => ({ pos: p, count: 1, days: days || 0 });
  return {
    objectName: seed.objectName || "",
    objectAddress: seed.objectAddress || "",
    execEntity: seed.execEntity || "fop",
    consequenceClass: seed.consequenceClass || "СС1",
    stage: seed.stage || "Робочий проєкт (РП)",
    gip: seed.gip || "",
    manDayRate: window.estimateManDay(),
    survey: {
      enabled: !window.isNewConstruction(seed.objectName),   // потрібне завжди, крім нового будівництва
      workName: "Технічне обстеження будівель і споруд",
      rows: [
        pos("Головний інженер проєкту"), pos("Архітектор"),
        pos("Інженер-проєктувальник КБ"), pos("Інженер-проєктувальник ОВ"),
        pos("Інженер-проєктувальник ВК"),
        pos("Інженерка з проєктно-кошторисної роботи"),
      ],
    },
    project: {
      workName: "Проєктні роботи",
      rows: [
        pos("Головний інженер проєкту"), pos("Архітектор"),
        pos("Інженер-проєктувальник КБ"), pos("Інженер-проєктувальник ОВ"),
        pos("Інженер-проєктувальник ВК"), pos("Еколог"),
        pos("Провідна інженерка з проєктно-кошторисної роботи"),
        pos("Інженерка з проєктно-кошторисної роботи"),
      ],
    },
    registration: {
      workName: "Реєстрація проєктної документації в ЄДЕССБ",
      rows: [pos("Директор", 1)],
    },
    expertise: {
      enabled: true, base: 0, sumNoVat: 0, vatPct: 20,
      calcText: "Експертиза за двома напрямами (міцність, надійність, довговічність та кошторисна частина). "
        + "Розрахунок згідно з Настановою з визначення вартості ПВР (наказ Мінрегіону № 281 від 01.11.2021), "
        + "розділ VII, п. 7.1–7.7, Додаток 6.",
    },
  };
};

// Зразок «Їдальня О-1» — заповнює трудовитрати й експертизу реальними числами.
window.estimateSampleO1 = function (est) {
  const days = { "Головний інженер проєкту": 2, "Архітектор": 2, "Інженер-проєктувальник КБ": 4,
    "Інженер-проєктувальник ОВ": 4, "Інженер-проєктувальник ВК": 4, "Еколог": 1,
    "Провідна інженерка з проєктно-кошторисної роботи": 0.5, "Інженерка з проєктно-кошторисної роботи": 5 };
  const e = JSON.parse(JSON.stringify(est || window.defaultEstimate()));
  e.project.rows = e.project.rows.map(r => ({ ...r, days: days[r.pos] != null ? days[r.pos] : r.days }));
  e.registration.rows = [{ pos: "Директор", count: 1, days: 1 }];
  e.expertise = { ...e.expertise, enabled: true, base: 22000000, sumNoVat: 20111.93, vatPct: 20 };
  if (!e.objectName) e.objectName = "Капітальний ремонт їдальні солдатської № 101300012 за генпланом літера «О-1» військової частини 3014 Національної гвардії України (м. Одеса)";
  if (!e.objectAddress) e.objectAddress = "м. Одеса, вул. Люстдорфська дорога, 7";
  return e;
};

// ─────────────────────────── Форматування чисел ───────────────────────────
function esFmt(n, min, max) {
  return Number(n || 0).toLocaleString("uk-UA", { minimumFractionDigits: min, maximumFractionDigits: max });
}
function esMoney(n) { return esFmt(n, 2, 2); }        // грн
function esNum3(n) { return esFmt(n, 2, 3); }         // люд-дн / показник (до 3 знаків)
function esThous(n) { return esFmt((Number(n) || 0) / 1000, 2, 6); } // тис грн (зведений)
function esWords(n) { return window.moneyInWords ? window.moneyInWords(esRound2(n)) : ""; }

// ═══════════════════════════ КОНСТРУКТОР ═══════════════════════════
function EstimateBuilder({ initial, seed, onClose, onSave }) {
  const [est, setEst] = React.useState(() => {
    const base = initial ? JSON.parse(JSON.stringify(initial)) : window.defaultEstimate(seed);
    if (!base.survey) base.survey = window.defaultEstimate(seed).survey;  // бекфіл блока «Технічне обстеження» для старих кошторисів
    return base;
  });
  const [rate, setRate] = React.useState(() => Object.assign({}, window.ESTIMATE_RATE || {}));
  const [showCalc, setShowCalc] = React.useState(false);
  const [savingRate, setSavingRate] = React.useState(false);
  const [rateSaved, setRateSaved] = React.useState(false);
  const [print, setPrint] = React.useState(false);
  // Обстеження авто-синхронізується з назвою об'єкта, поки користувач не перемкне галочку вручну.
  const [surveyAuto, setSurveyAuto] = React.useState(() => !initial);

  React.useEffect(() => {
    const onKey = (e) => e.key === "Escape" && !print && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose, print]);

  const calc = window.estimateRate(rate);           // живий показник (з полів калькулятора)
  const manDay = calc.manDay;
  const tot = window.estimateTotals(est, manDay);   // підсумки на поточному показнику

  const setE = (patch) => setEst(p => ({ ...p, ...patch }));
  const setRateField = (k, v) => { setRate(p => ({ ...p, [k]: v })); setRateSaved(false); };
  // Зміна назви об'єкта: якщо не перемикали галочку вручну — авто-вмикаємо/вимикаємо обстеження.
  const setObjectName = (v) => setEst(p => {
    const next = { ...p, objectName: v };
    if (surveyAuto && p.survey) next.survey = { ...p.survey, enabled: !window.isNewConstruction(v) };
    return next;
  });

  // рядки таблиць
  const editRow = (form, i, k, v) => setEst(p => {
    const rows = p[form].rows.slice(); rows[i] = { ...rows[i], [k]: v };
    return { ...p, [form]: { ...p[form], rows } };
  });
  const addRow = (form) => setEst(p => ({ ...p, [form]: { ...p[form], rows: [...p[form].rows, { pos: "", count: 1, days: 0 }] } }));
  const delRow = (form, i) => setEst(p => ({ ...p, [form]: { ...p[form], rows: p[form].rows.filter((_, j) => j !== i) } }));
  const setExp = (k, v) => setEst(p => ({ ...p, expertise: { ...p.expertise, [k]: v } }));
  const setFormEnabled = (form, v) => setEst(p => ({ ...p, [form]: { ...p[form], enabled: v } }));

  const applySample = () => setEst(window.estimateSampleO1(est));

  const saveRateGlobal = async () => {
    setSavingRate(true);
    const payload = window.estimateRatePayload(rate);
    try {
      if (window.API && window.API.put) await window.API.put("/estimate-rate", payload);
      window.ESTIMATE_RATE = payload;
      setRateSaved(true);
    } catch (e) {
      console.error("[ERP] save estimate-rate failed:", e);
      alert("Не вдалося зберегти показник на сервері.");
    } finally { setSavingRate(false); }
  };

  const doSave = () => {
    const out = JSON.parse(JSON.stringify(est));
    out.manDayRate = manDay;
    out.rateSnapshot = window.estimateRatePayload(rate);  // знімок параметрів показника (для аркуша «Розрахунок»)
    out.total = tot.grand;
    onSave && onSave(out, tot.grand);
    onClose();
  };

  // Викликаємо як функції (не як <JSX/>-компоненти), інакше React перемонтовує піддерево
  // на кожен рендер і поля вводу втрачають фокус після кожної клавіші.
  const rateRow = (n, label, val, unit) => (
    <div className="es-cr" key={n}><span className="es-cr-n">{n}</span><span className="es-cr-l">{label}</span>
      <span className="es-cr-v">{val}{unit ? <em> {unit}</em> : null}</span></div>
  );

  const renderFormTable = (form, title, subtitle, opts) => {
    opts = opts || {};
    const f = est[form];
    const enabled = !opts.togglable || f.enabled !== false;
    const heading = opts.num ? `Кошторис № ${opts.num} — ${title}` : title;
    const rows = f.rows;
    const sub = rows.reduce((s, r) => s + esN(r.count, 1) * esN(r.days) * manDay, 0);
    const vat = esRound2(sub * tot.worksVatPct / 100);
    return (
      <section className="es-block" key={form}>
        <div className="es-block-h">
          {opts.togglable
            ? <label style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <input type="checkbox" checked={enabled} onChange={e => (opts.onToggle ? opts.onToggle(e.target.checked) : setFormEnabled(form, e.target.checked))} />
                <b>{heading}</b> <span className="es-form-tag">{subtitle}</span></label>
            : <><b>{heading}</b> <span className="es-form-tag">{subtitle}</span></>}
          {opts.togglable && opts.hint && <span className="es-note" style={{ marginTop: 0, marginLeft: 8 }}>{opts.hint}</span>}
        </div>
        {enabled && <>
        <table className="es-tbl">
          <thead><tr>
            <th style={{ width: 28 }}>№</th><th>Найменування посад виконавців</th>
            <th style={{ width: 70 }}>К-сть, люд.</th><th style={{ width: 90 }}>Трудовитрати, люд.-дн.</th>
            <th style={{ width: 110 }}>Показник, грн/день</th><th style={{ width: 120 }}>Сума, грн</th><th style={{ width: 34 }}></th>
          </tr></thead>
          <tbody>
            {rows.map((r, i) => (
              <tr key={i}>
                <td className="es-c">{i + 1}</td>
                <td><input className="es-in" value={r.pos} onChange={e => editRow(form, i, "pos", e.target.value)} placeholder="Посада" /></td>
                <td><input className="es-in es-c" type="number" step="1" value={r.count} onChange={e => editRow(form, i, "count", e.target.value)} /></td>
                <td><input className="es-in es-c" type="number" step="0.5" value={r.days} onChange={e => editRow(form, i, "days", e.target.value)} /></td>
                <td className="es-r">{esNum3(manDay)}</td>
                <td className="es-r">{esNum3(esN(r.count, 1) * esN(r.days) * manDay)}</td>
                <td className="es-c"><button className="es-del" title="Видалити рядок" onClick={() => delRow(form, i)}>✕</button></td>
              </tr>
            ))}
            <tr className="es-total"><td colSpan={5} className="es-r">Разом{tot.worksVat ? " без ПДВ" : ""}:</td><td className="es-r">{esMoney(sub)}</td><td></td></tr>
            {tot.worksVat && <tr><td colSpan={5} className="es-r">ПДВ {tot.worksVatPct}%:</td><td className="es-r">{esMoney(vat)}</td><td></td></tr>}
            {tot.worksVat && <tr className="es-total"><td colSpan={5} className="es-r">Всього з ПДВ:</td><td className="es-r">{esMoney(esRound2(sub + vat))}</td><td></td></tr>}
          </tbody>
        </table>
        <button className="btn btn-sm" onClick={() => addRow(form)}>+ Рядок</button>
        </>}
      </section>
    );
  };

  return (
    <div className="ow-root">
      <EstimateBuilderStyles />
      <div className="ow-backdrop" onClick={onClose}></div>
      <div className="ow-modal es-modal">
        <div className="ow-head">
          <div>
            <div className="ow-title">Кошторис</div>
            <div className="ow-sub">форми 1-П · 2-П · 3-П · показник {esNum3(manDay)} грн/люд-день</div>
          </div>
          <button className="ow-x" onClick={onClose}><window.Ico name="plus" style={{ transform: "rotate(45deg)" }} /></button>
        </div>
        <div className="ow-body es-body">
          <div className="hint-box es-hint">
            <span>Заповніть трудовитрати (люд.-дні) — суми рахуються за показником. Зведений кошторис збереться автоматично.</span>
            <button className="btn" onClick={applySample}>Підставити зразок «Їдальня О-1»</button>
          </div>

          {/* Шапка об'єкта */}
          <div className="ow-grid">
            <label className="ow-field ow-wide"><span className="ow-label">Найменування об'єкта</span>
              <textarea rows={2} value={est.objectName} onChange={e => setObjectName(e.target.value)} placeholder="Капітальний ремонт …" /></label>
            <label className="ow-field ow-wide"><span className="ow-label">Адреса об'єкта</span>
              <input value={est.objectAddress} onChange={e => setE({ objectAddress: e.target.value })} placeholder="м. Одеса, вул. …" /></label>
            <label className="ow-field"><span className="ow-label">Виконавець</span>
              <select value={est.execEntity} onChange={e => setE({ execEntity: e.target.value })}>
                <option value="fop">ФОП (без ПДВ)</option><option value="tov">ТОВ (ПДВ)</option></select></label>
            <label className="ow-field"><span className="ow-label">Клас наслідків</span>
              <input value={est.consequenceClass} onChange={e => setE({ consequenceClass: e.target.value })} /></label>
            <label className="ow-field"><span className="ow-label">Стадія проєктування</span>
              <input value={est.stage} onChange={e => setE({ stage: e.target.value })} /></label>
            <label className="ow-field"><span className="ow-label">ГІП / ГАП</span>
              <input value={est.gip} onChange={e => setE({ gip: e.target.value })} placeholder="Олег МАРТИНЮК" /></label>
          </div>

          {/* Калькулятор показника */}
          <section className="es-block es-rate">
            <div className="es-block-h es-rate-h" onClick={() => setShowCalc(s => !s)}>
              <b>Показник вартості 1 люд-дня</b>
              <span className="es-rate-big">{esNum3(manDay)} грн</span>
              <span className="es-toggle">{showCalc ? "згорнути ▲" : "розрахунок ▼"}</span>
            </div>
            {showCalc && (
              <div className="es-rate-body">
                <div className="es-rate-inputs">
                  {[["hoursPerMonth", "Робочі години / місяць"], ["hoursPerDay", "Годин / день"],
                    ["baseIndicator", "Базовий показник, грн"], ["monthlyWageBase38", "Врахована ЗП 3,8 (міс.), грн"],
                    ["rankCoef7", "Міжрозрядний коеф. 7"], ["rankCoef38", "Міжрозрядний коеф. 3,8"],
                    ["esvPct", "ЄСВ, %"], ["currentWage38", "Поточна ЗП 3,8, грн"], ["year", "Рік"]].map(([k, l]) => (
                    <label key={k} className="es-ri"><span>{l}</span>
                      <input type="number" step="any" value={rate[k] != null ? rate[k] : (window.ESTIMATE_RATE || {})[k] || ""}
                        onChange={e => setRateField(k, e.target.value)} /></label>
                  ))}
                </div>
                <div className="es-rate-derived">
                  {rateRow("1.3", "Робочих днів / місяць", esFmt(calc.daysPerMonth, 2, 4))}
                  {rateRow("1.6", "ЗП 1 люд-дня (3,8)", esFmt(calc.dailyWageBase38, 2, 4), "грн")}
                  {rateRow("1.9", "Коеф. між 7 та 3,8", esFmt(calc.rankRatio, 2, 4))}
                  {rateRow("1.10", "ЗП 1 люд-дня (7)", esFmt(calc.dailyWage7, 2, 4), "грн")}
                  {rateRow("1.11", "Питома вага ЗП", esFmt(calc.shareWage, 2, 4))}
                  {rateRow("1.14", "Питома вага ЗП з ЄСВ", esFmt(calc.shareWageWithEsv, 2, 4))}
                  {rateRow("2.1", "Інші статті витрат", esFmt(calc.shareOther, 2, 4))}
                  {rateRow("3.3", "Коеф. зміни ЗП", esFmt(calc.coefWageChange, 2, 5))}
                  {rateRow("3.4", "Коеф. договірної вартості", esFmt(calc.coefContract, 2, 4))}
                  {rateRow("4", "Показник 1 люд-дня", esNum3(calc.manDay), "грн")}
                </div>
                <div className="es-rate-foot">
                  <span className="es-rate-note">Показник — глобальний: застосовується до всіх кошторисів.</span>
                  {rateSaved && <span className="es-saved">✓ збережено</span>}
                  <button className="btn btn-sm" disabled={savingRate} onClick={saveRateGlobal}>{savingRate ? "…" : "Зберегти показник глобально"}</button>
                </div>
              </div>
            )}
          </section>

          {renderFormTable("survey", "Технічне обстеження будівель і споруд", "форма 3-П",
            { togglable: true, num: tot.num.survey,
              hint: surveyAuto ? "авто: не потрібне лише для нового будівництва" : "не потрібне лише для нового будівництва",
              onToggle: (v) => { setSurveyAuto(false); setFormEnabled("survey", v); } })}
          {renderFormTable("project", "Проєктні роботи", "форма 3-П", { num: tot.num.project })}
          {renderFormTable("registration", "Реєстрація проєктної документації в ЄДЕССБ", "форма 3-П", { num: tot.num.registration })}

          {/* Експертиза */}
          <section className="es-block">
            <div className="es-block-h">
              <label style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <input type="checkbox" checked={est.expertise.enabled !== false} onChange={e => setExp("enabled", e.target.checked)} />
                <b>Кошторис № {tot.num.expertise || "—"} — Експертиза</b> <span className="es-form-tag">форма 2-П</span>
              </label>
            </div>
            {est.expertise.enabled !== false && (
              <div className="es-exp">
                <div className="ow-grid">
                  <label className="ow-field"><span className="ow-label">Розрахункова база (вартість буд-робіт), грн</span>
                    <input type="number" step="0.01" value={est.expertise.base} onChange={e => setExp("base", e.target.value)} placeholder="22000000" /></label>
                  <label className="ow-field"><span className="ow-label">Вартість експертизи без ПДВ, грн</span>
                    <input type="number" step="0.01" value={est.expertise.sumNoVat} onChange={e => setExp("sumNoVat", e.target.value)} placeholder="20111.93" /></label>
                  <label className="ow-field"><span className="ow-label">ПДВ, %</span>
                    <input type="number" step="0.01" value={est.expertise.vatPct} onChange={e => setExp("vatPct", e.target.value)} /></label>
                  <label className="ow-field ow-wide"><span className="ow-label">Обґрунтування розрахунку</span>
                    <textarea rows={2} value={est.expertise.calcText} onChange={e => setExp("calcText", e.target.value)} /></label>
                </div>
                <div className="es-exp-sum">
                  <span>Разом без ПДВ: <b>{esMoney(tot.expNoVat)}</b></span>
                  <span>ПДВ {esN(est.expertise.vatPct, 20)}%: <b>{esMoney(tot.expVat)}</b></span>
                  <span>Всього: <b>{esMoney(tot.expTotal)}</b> грн</span>
                </div>
                <div className="es-note">Точний розрахунок % за Додатком 6 Настанови (автоінтерполяція) — окремим оновленням; поки сума вводиться вручну.</div>
              </div>
            )}
          </section>

          {/* Зведений */}
          <section className="es-block">
            <div className="es-block-h"><b>Кошторис № 1 — Зведений</b> <span className="es-form-tag">форма 1-П · авто</span></div>
            <table className="es-tbl">
              <thead><tr><th style={{ width: 28 }}>№</th><th>Перелік робіт</th><th style={{ width: 60 }}>Форма</th>
                <th className="es-r">Вишукув., грн</th><th className="es-r">Проєктні, грн</th><th className="es-r">Додаткові, грн</th><th className="es-r">Всього, грн</th></tr></thead>
              <tbody>
                {tot.surveyEnabled && <tr><td className="es-c">{tot.num.survey - 1}</td><td>Технічне обстеження будівель і споруд</td><td className="es-c">3-П</td><td className="es-r">{esMoney(tot.surveyExact)}</td><td className="es-r">—</td><td className="es-r">—</td><td className="es-r">{esMoney(tot.surveyExact)}</td></tr>}
                <tr><td className="es-c">{tot.num.project - 1}</td><td>Проєктні роботи</td><td className="es-c">3-П</td><td className="es-r">—</td><td className="es-r">{esMoney(tot.projectExact)}</td><td className="es-r">—</td><td className="es-r">{esMoney(tot.projectExact)}</td></tr>
                <tr><td className="es-c">{tot.num.registration - 1}</td><td>Реєстрація в ЄДЕССБ</td><td className="es-c">3-П</td><td className="es-r">—</td><td className="es-r">—</td><td className="es-r">{esMoney(tot.registrationExact)}</td><td className="es-r">{esMoney(tot.registrationExact)}</td></tr>
                {tot.expEnabled && <tr><td className="es-c">{tot.num.expertise - 1}</td><td>Експертиза</td><td className="es-c">2-П</td><td className="es-r">—</td><td className="es-r">—</td><td className="es-r">{esMoney(tot.expExact)}</td><td className="es-r">{esMoney(tot.expExact)}</td></tr>}
                <tr className="es-total"><td colSpan={3} className="es-r">Разом{tot.worksVat ? " без ПДВ на роботи" : ""}:</td><td className="es-r">{esMoney(tot.summary.vyshukuvalnyh)}</td><td className="es-r">{esMoney(tot.summary.proektnih)}</td><td className="es-r">{esMoney(tot.summary.dodatkovih)}</td><td className="es-r">{esMoney(tot.summary.vsogo)}</td></tr>
                {tot.worksVat && <tr><td colSpan={6} className="es-r">ПДВ {tot.worksVatPct}% на проєктні роботи{tot.surveyEnabled ? ", обстеження" : ""} та реєстрацію:</td><td className="es-r">{esMoney(tot.worksVatSum)}</td></tr>}
              </tbody>
            </table>
            <div className="es-grand">Всього за зведеним кошторисом{tot.worksVat ? " (з ПДВ)" : ""}: <b>{esMoney(tot.grand)} грн</b> <span className="es-grand-w">({esWords(tot.grand)})</span></div>
          </section>
        </div>
        <div className="ow-foot">
          <span className="ow-foot-hint">Кошторис збережеться в КП; вартість КП = {esMoney(tot.grand)} грн.</span>
          <button className="btn" onClick={() => setPrint(true)}><window.Ico name="download" /> Друк</button>
          <button className="btn" onClick={onClose}>Скасувати</button>
          <button className="btn btn-primary" onClick={doSave}>Зберегти кошторис</button>
        </div>
      </div>
      {print && <EstimatePrintDoc est={{ ...est, manDayRate: manDay }} meta={seed || {}} rate={rate} context="proposal" onClose={() => setPrint(false)} />}
    </div>
  );
}
window.EstimateBuilder = EstimateBuilder;

// ═══════════════════════════ ДРУК (6 аркушів) ═══════════════════════════
function EsSheet({ children, label, co }) {
  co = co || window.COMPANY || {};
  return (
    <div className="es-sheet">
      <div className="es-sheet-body">{children}</div>
      <div className="es-foot">
        <div className="es-foot-l">{co.tmText || "УКРБУДПРОЄКТ® — зареєстрована торговельна марка"}<br />{co.tmCert || ""}</div>
        <div className="es-foot-c">🇺🇦 Слава Україні · Героям слава</div>
        <div className="es-foot-r">{label || ""}</div>
      </div>
    </div>
  );
}

function EsSign({ exec, gip, withKerivnyk }) {
  return (
    <div className="es-sign">
      {withKerivnyk && <div className="es-sign-row"><span>Керівник проєктної (науково-проєктної, вишукувальної) організації</span><span className="es-sign-name">{exec.directorSign || exec.directorFull}</span></div>}
      <div className="es-sign-row"><span>Головний інженер проєкту (Головний архітектор проєкту)</span><span className="es-sign-name">{gip || "________"}</span></div>
      <div className="es-sign-row"><span>Кошторис склала</span><span className="es-sign-name">{exec.directorSign || exec.directorFull}</span></div>
      <div className="es-mp">М.П. &nbsp; «____» _____________ 20___ р.</div>
    </div>
  );
}

function EsObjHead({ exec, objFull }) {
  return (<>
    <div className="es-p-obj">{objFull}</div>
    <div className="es-p-cap">(найменування об'єкта будівництва)</div>
    <div className="es-p-org">Найменування проєктної (науково-проєктної, вишукувальної) організації:<br /><b>{exec.fullName}</b></div>
  </>);
}

function EsLaborSheet({ est, form, n, title, manDay, exec, co, k }) {
  const rows = (est[form] && est[form].rows) || [];
  const objFull = (est.objectName || "[найменування об'єкта будівництва]") + (est.objectAddress ? " за адресою: " + est.objectAddress : "");
  const sub = rows.reduce((s, r) => s + esN(r.count, 1) * esN(r.days) * manDay, 0);
  const worksVat = est.execEntity === "tov";
  const worksVatPct = worksVat ? esN(est.worksVatPct, 20) : 0;
  const vat = esRound2(sub * worksVatPct / 100);
  const withVat = esRound2(sub + vat);
  return (
    <EsSheet key={k} label={`Кошторис № ${n} · форма 3-П`} co={co}>
      <div className="es-p-h1">КОШТОРИС № {n}</div>
      <div className="es-p-h2">на виконання робіт «{title}»</div>
      <div className="es-p-form">Форма № 3-П</div>
      <EsObjHead exec={exec} objFull={objFull} />
      <table className="es-ptbl">
        <thead><tr>
          <th>Ч.ч.</th><th>Перелік робіт, що виконуються</th><th>Найменування посад виконавців</th>
          <th>К-сть викон., люд.</th><th>Трудовитрати, люд.-дн.</th><th>Показник за 1 день, грн</th><th>Всього, грн</th>
        </tr></thead>
        <tbody>
          {rows.map((r, i) => (
            <tr key={i}>
              {i === 0 && <td className="es-c" rowSpan={rows.length}>{1}</td>}
              {i === 0 && <td rowSpan={rows.length}>{title}</td>}
              <td>{r.pos}</td><td className="es-c">{esN(r.count, 1)}</td>
              <td className="es-c">{esFmt(r.days, 0, 2)}</td><td className="es-r">{esNum3(manDay)}</td><td className="es-r">{esNum3(esN(r.count, 1) * esN(r.days) * manDay)}</td>
            </tr>
          ))}
          <tr className="es-ptotal"><td colSpan={6} className="es-r">Разом{worksVat ? " без ПДВ" : ""}</td><td className="es-r">{esMoney(sub)}</td></tr>
          {worksVat && <tr><td colSpan={6} className="es-r">ПДВ {worksVatPct} %</td><td className="es-r">{esMoney(vat)}</td></tr>}
          {worksVat && <tr className="es-ptotal"><td colSpan={6} className="es-r">Всього з ПДВ</td><td className="es-r">{esMoney(withVat)}</td></tr>}
        </tbody>
      </table>
      <div className="es-p-vsogo">Всього за кошторисом — <b>{esMoney(withVat)} грн</b> ({esWords(withVat)}){worksVat ? <>, у т. ч. ПДВ {worksVatPct}% — {esMoney(vat)} грн</> : null}</div>
      <EsSign exec={exec} gip={est.gip} />
    </EsSheet>
  );
}

// Аркуші кошторису як переносний список — і для окремого друку, і для друку договору.
// opts: { rate, meta:{customer,contractNumber,contractDate,proposalNumber,proposalDate}, includeTitle,
//         context:"proposal"|"contract" }. У КП («proposal») НЕ пишемо «Додаток № 4 до Договору» —
//         договору ще немає; це просто КОШТОРИС. «Додаток № 4» — лише в контексті договору.
window.EstimateSheets = function (est, opts) {
  opts = opts || {};
  const meta = opts.meta || {};
  const isContract = opts.context === "contract";
  const co = window.COMPANY || {};
  const exec = window.execEntity ? window.execEntity(est.execEntity || "fop") : co;
  const calc = window.estimateRate(est.rateSnapshot || opts.rate);
  const manDay = est.manDayRate || calc.manDay;
  const tot = window.estimateTotals(est, manDay);
  const objFull = (est.objectName || "[найменування об'єкта будівництва]") + (est.objectAddress ? " за адресою: " + est.objectAddress : "");
  const cNum = meta.contractNumber || "_________";
  const cDate = meta.contractDate || "«___» ___________ 20___ р.";
  const titleWord = isContract ? "КОШТОРИСИ" : "КОШТОРИС";
  const sheetLabel = isContract ? "Додаток № 4 — Кошториси" : "Кошторис";
  const compHead = isContract ? "Склад Додатка № 4:" : "Склад кошторису:";
  const sheets = [];

  if (opts.includeTitle !== false) {
    sheets.push(
      <EsSheet key="title" label={sheetLabel} co={co}>
        {isContract
          ? <div className="es-p-ref">Додаток № 4<br />до Договору № {cNum}<br />від {cDate}</div>
          : (meta.proposalNumber ? <div className="es-p-ref">до комерційної пропозиції № {meta.proposalNumber}{meta.proposalDate ? <> від {meta.proposalDate}</> : null}</div> : null)}
        <div className="es-p-h1" style={{ marginTop: isContract ? 28 : 8 }}>{titleWord}</div>
        <div className="es-p-h2">на роботи з розроблення проєктно-кошторисної документації та супроводу експертизи</div>
        <div className="es-p-obj">по об'єкту: «{objFull}»</div>
        <div className="es-p-meta">
          <div><span>Замовник:</span> {meta.customer || "________"}</div>
          <div><span>Виконавець:</span> {exec.fullName}</div>
          <div><span>Клас наслідків (відповідальності):</span> {est.consequenceClass || "СС1"}</div>
          <div><span>Стадія проєктування:</span> {est.stage || "Робочий проєкт (РП)"}</div>
        </div>
        <div className="es-p-list">{compHead}
          <ul>
            <li>Кошторис № 1 — Зведений кошторис на проєктні, науково-проєктні, вишукувальні роботи (форма 1-П)</li>
            {tot.surveyEnabled && <li>Кошторис № {tot.num.survey} — Кошторис на виконання робіт «Технічне обстеження будівель і споруд» (форма 3-П)</li>}
            <li>Кошторис № {tot.num.project} — Кошторис на виконання робіт «Проєктні роботи» (форма 3-П)</li>
            <li>Кошторис № {tot.num.registration} — Кошторис на виконання робіт «Реєстрація проєктної документації в ЄДЕССБ» (форма 3-П)</li>
            {tot.expEnabled && <li>Кошторис № {tot.num.expertise} — Кошторис на роботи «Експертиза» (форма 2-П)</li>}
            <li>Розрахунок показника кошторисної вартості в розрахунку на 1 людино-день</li>
          </ul>
        </div>
      </EsSheet>
    );
  }

  sheets.push(
    <EsSheet key="summary" label="Кошторис № 1 · форма 1-П" co={co}>
      <div className="es-p-h1">ЗВЕДЕНИЙ КОШТОРИС № 1</div>
      <div className="es-p-h2">на проєктні, науково-проєктні, вишукувальні роботи</div>
      <div className="es-p-form">Форма № 1-П</div>
      <EsObjHead exec={exec} objFull={objFull} />
      <table className="es-ptbl">
        <thead>
          <tr><th rowSpan={2}>Ч.ч.</th><th rowSpan={2}>Стадія проєктування і перелік робіт</th><th rowSpan={2}>Найменування виду робіт</th><th rowSpan={2}>№ кошто-рисів</th><th colSpan={4}>Повна вартість робіт, тис. грн</th></tr>
          <tr><th>вишу-кувальних</th><th>проєктних</th><th>додатко-вих*</th><th>всього</th></tr>
        </thead>
        <tbody>
          {tot.surveyEnabled && <tr><td className="es-c">{tot.num.survey - 1}</td><td>{est.stage || "Робочий проєкт"}</td><td>Технічне обстеження будівель і споруд</td><td className="es-c">{tot.num.survey}</td><td className="es-r">{esThous(tot.surveyExact)}</td><td className="es-r">—</td><td className="es-r">—</td><td className="es-r">{esThous(tot.surveyExact)}</td></tr>}
          <tr><td className="es-c">{tot.num.project - 1}</td><td>{est.stage || "Робочий проєкт"}</td><td>Проєктні роботи</td><td className="es-c">{tot.num.project}</td><td className="es-r">—</td><td className="es-r">{esThous(tot.projectExact)}</td><td className="es-r">—</td><td className="es-r">{esThous(tot.projectExact)}</td></tr>
          <tr><td className="es-c">{tot.num.registration - 1}</td><td>{est.stage || "Робочий проєкт"}</td><td>Реєстрація в ЄДЕССБ</td><td className="es-c">{tot.num.registration}</td><td className="es-r">—</td><td className="es-r">—</td><td className="es-r">{esThous(tot.registrationExact)}</td><td className="es-r">{esThous(tot.registrationExact)}</td></tr>
          {tot.expEnabled && <tr><td className="es-c">{tot.num.expertise - 1}</td><td>{est.stage || "Робочий проєкт"}</td><td>Експертиза</td><td className="es-c">{tot.num.expertise}</td><td className="es-r">—</td><td className="es-r">—</td><td className="es-r">{esThous(tot.expExact)}</td><td className="es-r">{esThous(tot.expExact)}</td></tr>}
          <tr className="es-ptotal"><td colSpan={4} className="es-r">Разом{tot.worksVat ? " без ПДВ" : ""}</td><td className="es-r">{esThous(tot.summary.vyshukuvalnyh)}</td><td className="es-r">{esThous(tot.summary.proektnih)}</td><td className="es-r">{esThous(tot.summary.dodatkovih)}</td><td className="es-r">{esThous(tot.summary.vsogo)}</td></tr>
          {tot.worksVat && <tr><td colSpan={7} className="es-r">ПДВ {tot.worksVatPct} % на проєктні роботи{tot.surveyEnabled ? ", обстеження" : ""} та реєстрацію</td><td className="es-r">{esThous(tot.worksVatSum)}</td></tr>}
          {tot.worksVat && <tr className="es-ptotal"><td colSpan={7} className="es-r">Всього з ПДВ</td><td className="es-r">{esThous(tot.grand)}</td></tr>}
        </tbody>
      </table>
      <div className="es-p-note">Примітка: * Враховуються у разі, якщо ці роботи виконуються за дорученням замовника.{exec.vatPayer ? " Вартість проєктних робіт" + (tot.surveyEnabled ? ", технічного обстеження" : "") + " і реєстрації наведена з урахуванням ПДВ " + esN(tot.worksVatPct, 20) + " %." : " " + (exec.shortName || "ФОП") + " не є платником ПДВ."} Експертиза проєктної документації включає ПДВ у складі вартості послуг експертної організації.</div>
      <div className="es-p-vsogo">Всього за зведеним кошторисом — <b>{esMoney(tot.grand)} грн</b> ({esWords(tot.grand)}){tot.worksVat ? <>, у т. ч. ПДВ на роботи {esN(tot.worksVatPct, 20)}% — {esMoney(tot.worksVatSum)} грн</> : null}</div>
      <EsSign exec={exec} gip={est.gip} withKerivnyk />
    </EsSheet>
  );

  if (tot.surveyEnabled)
    sheets.push(<EsLaborSheet k="p-survey" est={est} form="survey" n={tot.num.survey} title="Технічне обстеження будівель і споруд" manDay={manDay} exec={exec} co={co} />);
  sheets.push(<EsLaborSheet k="p2" est={est} form="project" n={tot.num.project} title="Проєктні роботи" manDay={manDay} exec={exec} co={co} />);
  sheets.push(<EsLaborSheet k="p3" est={est} form="registration" n={tot.num.registration} title="Реєстрація проєктної документації в ЄДЕССБ" manDay={manDay} exec={exec} co={co} />);

  if (tot.expEnabled) {
    sheets.push(
      <EsSheet key="p4" label={`Кошторис № ${tot.num.expertise} · форма 2-П`} co={co}>
        <div className="es-p-h1">КОШТОРИС № {tot.num.expertise}</div>
        <div className="es-p-h2">на проєктні, науково-проєктні, вишукувальні роботи «Експертиза»</div>
        <div className="es-p-form">Форма № 2-П</div>
        <EsObjHead exec={exec} objFull={objFull} />
        <table className="es-ptbl">
          <thead><tr><th>Ч.ч.</th><th>Характеристика виду робіт</th><th>Назва документа обґрунтування</th><th>Вартість, грн</th></tr></thead>
          <tbody>
            <tr><td className="es-c">1</td><td>{est.expertise.calcText}</td><td className="es-c">Настанова, наказ Мінрегіону № 281 від 01.11.2021, розділ VII, Додаток 6{est.expertise.base ? "; розрахункова база " + esMoney(est.expertise.base) + " грн" : ""}</td><td className="es-r">{esMoney(tot.expNoVat)}</td></tr>
            <tr className="es-ptotal"><td colSpan={3} className="es-r">Разом по кошторису, грн</td><td className="es-r">{esMoney(tot.expNoVat)}</td></tr>
            <tr><td colSpan={3} className="es-r">ПДВ ({esN(est.expertise.vatPct, 20)} %)</td><td className="es-r">{esMoney(tot.expVat)}</td></tr>
            <tr className="es-ptotal"><td colSpan={3} className="es-r">Всього, грн</td><td className="es-r">{esMoney(tot.expTotal)}</td></tr>
          </tbody>
        </table>
        <div className="es-p-vsogo">Всього за кошторисом — <b>{esMoney(tot.expTotal)} грн</b> ({esWords(tot.expTotal)}), у т. ч. ПДВ {esN(est.expertise.vatPct, 20)}% — {esMoney(tot.expVat)} грн</div>
        <EsSign exec={exec} gip={est.gip} />
      </EsSheet>
    );
  }

  sheets.push(
    <EsSheet key="rate" label="Розрахунок показника" co={co}>
      <div className="es-p-h1">РОЗРАХУНОК ПОКАЗНИКА КОШТОРИСНОЇ ВАРТОСТІ</div>
      <div className="es-p-h2">в розрахунку на 1 людино-день (коефіцієнт зміни рівня заробітної плати)</div>
      <table className="es-ptbl es-ptbl-l">
        <thead><tr><th>№</th><th>Елементи витрат</th><th>Значення</th><th>Од.</th></tr></thead>
        <tbody>
          <tr><td className="es-c">1.1</td><td>Кількість робочих годин на місяць ({calc.year || 2026})</td><td className="es-r">{esFmt(calc.hoursPerMonth, 2, 2)}</td><td className="es-c">год.</td></tr>
          <tr><td className="es-c">1.2</td><td>Кількість робочих годин на день</td><td className="es-r">{esFmt(calc.hoursPerDay, 2, 2)}</td><td className="es-c">год.</td></tr>
          <tr><td className="es-c">1.3</td><td>Кількість робочих днів на місяць</td><td className="es-r">{esFmt(calc.daysPerMonth, 2, 4)}</td><td className="es-c">день</td></tr>
          <tr><td className="es-c">1.4</td><td>Базовий показник кошторисної вартості 1 люд-дня</td><td className="es-r">{esMoney(calc.baseIndicator)}</td><td className="es-c">грн</td></tr>
          <tr><td className="es-c">1.5</td><td>Врахована ЗП у вартості 1 люд-дня (розряд 3,8)</td><td className="es-r">{esMoney(calc.monthlyWageBase38)}</td><td className="es-c">грн</td></tr>
          <tr><td className="es-c">1.6</td><td>ЗП у вартості людино-дня (розряд 3,8)</td><td className="es-r">{esFmt(calc.dailyWageBase38, 2, 4)}</td><td className="es-c">грн</td></tr>
          <tr><td className="es-c">1.7</td><td>Міжрозрядний коефіцієнт для 7 розряду</td><td className="es-r">{esFmt(calc.rankCoef7, 2, 3)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">1.8</td><td>Міжрозрядний коефіцієнт для розряду 3,8</td><td className="es-r">{esFmt(calc.rankCoef38, 2, 3)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">1.9</td><td>Коефіцієнт між розрядами 7 та 3,8</td><td className="es-r">{esFmt(calc.rankRatio, 2, 4)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">1.10</td><td>ЗП у вартості людино-дня (розряд 7)</td><td className="es-r">{esFmt(calc.dailyWage7, 2, 4)}</td><td className="es-c">грн</td></tr>
          <tr><td className="es-c">1.11</td><td>Питома вага ЗП у показнику</td><td className="es-r">{esFmt(calc.shareWage, 2, 4)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">1.13</td><td>Розмір ЄСВ</td><td className="es-r">{esFmt(calc.esvPct, 2, 2)}</td><td className="es-c">%</td></tr>
          <tr><td className="es-c">1.14</td><td>Питома вага ЗП з урахуванням ЄСВ</td><td className="es-r">{esFmt(calc.shareWageWithEsv, 2, 4)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">2.1</td><td>Питома вага інших статей витрат</td><td className="es-r">{esFmt(calc.shareOther, 2, 4)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">3.1</td><td>ЗП для розряду 3,8 (поточний рівень)</td><td className="es-r">{esMoney(calc.currentWage38)}</td><td className="es-c">грн</td></tr>
          <tr><td className="es-c">3.2</td><td>ЗП для розряду 7 (поточний рівень)</td><td className="es-r">{esMoney(calc.currentWage7)}</td><td className="es-c">грн</td></tr>
          <tr><td className="es-c">3.3</td><td>Коефіцієнт зміни заробітної плати</td><td className="es-r">{esFmt(calc.coefWageChange, 2, 5)}</td><td className="es-c"></td></tr>
          <tr><td className="es-c">3.4</td><td>Коефіцієнт для договірної вартості проєктних робіт</td><td className="es-r">{esFmt(calc.coefContract, 2, 4)}</td><td className="es-c"></td></tr>
          <tr className="es-ptotal"><td className="es-c">4</td><td>Показник кошторисної вартості на 1 людино-день</td><td className="es-r">{esNum3(calc.manDay)}</td><td className="es-c">грн</td></tr>
        </tbody>
      </table>
      <div className="es-p-note">Розрахунок виконаний на підставі КНУ «Настанова з визначення вартості проєктних, науково-проєктних, вишукувальних робіт та експертизи проєктної документації на будівництво» (наказ Мінрегіону № 281 від 01.11.2021, п. 2.8–2.9), з використанням офіційних даних Держстату щодо середньомісячної номінальної заробітної плати.</div>
      <EsSign exec={exec} gip={est.gip} />
    </EsSheet>
  );

  return sheets;
};

function EstimatePrintDoc({ est, meta, rate, onClose, context }) {
  React.useEffect(() => {
    const onKey = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);
  React.useEffect(() => { document.body.classList.add("lt-open"); return () => document.body.classList.remove("lt-open"); }, []);
  const ctx = context || "proposal";  // друк із КП → не «Додаток № 4»; договір рендерить через EstimateSheets окремо
  const exec = window.execEntity ? window.execEntity((est || {}).execEntity || "fop") : (window.COMPANY || {});
  const doPrint = () => window.print();
  const sheets = window.EstimateSheets(est, { meta: meta || {}, rate, includeTitle: true, context: ctx });
  return ReactDOM.createPortal(
    <React.Fragment>
      <EstimatePrintStyles />
      <div className="es-proot">
        <div className="es-pbackdrop" onClick={onClose}></div>
        <div className="es-ptoolbar">
          <div className="es-ptoolbar-title">{ctx === "contract" ? "Додаток № 4 · Кошториси" : "Кошторис"} · {exec.shortName}</div>
          <div className="es-ptoolbar-actions">
            <button className="btn" onClick={onClose}>Закрити</button>
            <button className="btn btn-primary" onClick={doPrint}><window.Ico name="download" /> Друк / PDF</button>
          </div>
        </div>
        <div className="es-pscroll">{sheets}</div>
      </div>
    </React.Fragment>,
    document.body
  );
}
window.EstimatePrintDoc = EstimatePrintDoc;

// ═══════════════════════════ Стилі ═══════════════════════════
function EstimateBuilderStyles() {
  return (<style>{`
    .es-modal { width: 940px; max-width: 96vw; }
    .es-body { max-height: 74vh; overflow-y: auto; }
    .es-hint { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
    .es-block { margin: 16px 0; border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; background: var(--bg-elev); }
    .es-block-h { font-size: 13.5px; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
    .es-form-tag { font-size: 11px; color: var(--ink-3); font-weight: 500; background: var(--bg); padding: 1px 7px; border-radius: 20px; }
    .es-tbl { width: 100%; border-collapse: collapse; margin: 4px 0 8px; }
    .es-tbl th { font-size: 10.5px; color: var(--ink-3); font-weight: 600; text-align: left; padding: 4px 6px; border-bottom: 1px solid var(--line); }
    .es-tbl td { padding: 3px 6px; border-bottom: 1px solid var(--line-2, var(--line)); font-size: 12.5px; vertical-align: middle; }
    .es-tbl .es-c { text-align: center; } .es-tbl .es-r { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
    .es-tbl th.es-r { text-align: right; }
    .es-in { width: 100%; border: 1px solid transparent; background: transparent; padding: 4px 6px; border-radius: 6px; font: inherit; color: var(--ink); }
    .es-in:hover { border-color: var(--line); } .es-in:focus { border-color: var(--accent); background: var(--bg); outline: none; }
    .es-in.es-c { text-align: center; }
    .es-del { border: none; background: transparent; color: var(--ink-3); cursor: pointer; font-size: 13px; padding: 2px 6px; border-radius: 6px; }
    .es-del:hover { background: var(--danger-bg, #fde8e8); color: var(--danger, #c0392b); }
    .es-total td { font-weight: 700; border-top: 2px solid var(--line); border-bottom: none; padding-top: 6px; }
    .es-rate { background: linear-gradient(180deg, var(--bg-elev), var(--bg)); }
    .es-rate-h { cursor: pointer; justify-content: space-between; }
    .es-rate-big { font-size: 16px; font-weight: 800; color: var(--accent); margin-left: auto; }
    .es-toggle { font-size: 11px; color: var(--ink-3); }
    .es-rate-inputs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px 12px; margin-bottom: 10px; }
    .es-ri { display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: var(--ink-3); }
    .es-ri input { border: 1px solid var(--line); border-radius: 6px; padding: 5px 7px; font: inherit; font-size: 12.5px; color: var(--ink); background: var(--bg); }
    .es-rate-derived { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px 18px; padding: 8px 0; border-top: 1px dashed var(--line); }
    .es-cr { display: flex; align-items: baseline; gap: 8px; font-size: 11.5px; padding: 2px 0; }
    .es-cr-n { color: var(--ink-3); width: 30px; } .es-cr-l { flex: 1; color: var(--ink-2, var(--ink)); } .es-cr-v { font-weight: 700; font-variant-numeric: tabular-nums; } .es-cr-v em { font-style: normal; color: var(--ink-3); font-weight: 400; }
    .es-rate-foot { display: flex; align-items: center; gap: 10px; padding-top: 8px; border-top: 1px dashed var(--line); }
    .es-rate-note { font-size: 11px; color: var(--ink-3); margin-right: auto; }
    .es-saved { font-size: 12px; color: var(--ok, #2e7d32); font-weight: 600; }
    .es-exp-sum { display: flex; gap: 20px; flex-wrap: wrap; font-size: 12.5px; margin: 6px 0; }
    .es-note, .es-p-note { font-size: 11px; color: var(--ink-3); font-style: italic; margin-top: 6px; line-height: 1.5; }
    .es-grand { margin-top: 8px; font-size: 14px; } .es-grand b { color: var(--accent); font-size: 16px; } .es-grand-w { color: var(--ink-3); font-size: 12px; }
    @media (max-width: 760px) { .es-rate-inputs, .es-rate-derived { grid-template-columns: 1fr; } }
  `}</style>);
}

// Стилі самих аркушів кошторису — потрібні і в окремому друку, і всередині друку договору.
function EstimateSheetStyles() {
  return (<style id="es-sheet-styles">{`
    .es-sheet { width: 210mm; max-width: 100%; min-height: 297mm; background: #fff; color: #1a1a1a; padding: 14mm 16mm 10mm; box-shadow: 0 18px 50px rgba(0,0,0,.32); box-sizing: border-box; font-family: "PT Serif","Times New Roman",Georgia,serif; line-height: 1.4; font-size: 11px; display: flex; flex-direction: column; }
    .es-sheet-body { flex: 1 1 auto; }
    .es-p-ref { text-align: right; font-size: 11px; line-height: 1.4; }
    .es-p-h1 { font-size: 14px; font-weight: 700; text-align: center; margin: 6px 0 3px; }
    .es-p-h2 { font-size: 11.5px; text-align: center; margin-bottom: 2px; }
    .es-p-form { text-align: center; font-size: 11px; font-weight: 700; margin-bottom: 8px; }
    .es-p-obj { text-align: center; font-size: 11px; font-weight: 600; margin: 6px 0 2px; text-wrap: pretty; }
    .es-p-cap { text-align: center; font-size: 9.5px; color: #6b7780; margin-bottom: 6px; }
    .es-p-org { font-size: 10.5px; margin: 4px 0 10px; }
    .es-p-meta { display: grid; grid-template-columns: 1fr; gap: 3px; font-size: 11px; margin: 12px 0; }
    .es-p-meta span { color: #6b7780; }
    .es-p-list { font-size: 10.5px; margin-top: 14px; } .es-p-list ul { margin: 6px 0 0; padding-left: 18px; } .es-p-list li { margin-bottom: 3px; }
    .es-ptbl { width: 100%; border-collapse: collapse; margin: 8px 0 10px; }
    .es-ptbl th { background: #eef3f4; border: 1px solid #b9c4ca; padding: 4px 5px; font-size: 8.8px; font-weight: 700; text-align: center; line-height: 1.25; }
    .es-ptbl td { border: 1px solid #c8d1d6; padding: 4px 6px; font-size: 10px; vertical-align: top; }
    .es-ptbl .es-c { text-align: center; } .es-ptbl .es-r { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
    .es-ptbl-l td:nth-child(2) { text-align: left; }
    .es-ptotal td { font-weight: 700; background: #f6f9f9; }
    .es-p-vsogo { font-size: 11px; font-weight: 600; margin: 8px 0; text-wrap: pretty; }
    .es-sign { margin-top: 16px; }
    .es-sign-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 11px; border-bottom: 1px solid #c8d1d6; padding-bottom: 3px; }
    .es-sign-row span:first-child { font-size: 10px; color: #4a555c; }
    .es-sign-name { font-size: 10.5px; font-weight: 700; white-space: nowrap; }
    .es-mp { font-size: 10px; color: #6b7780; margin-top: 8px; }
    .es-foot { margin-top: 14px; padding-top: 8px; border-top: 1px solid #e3e9ea; display: flex; justify-content: space-between; gap: 14px; font-family: "Nunito Sans", system-ui, sans-serif; font-size: 8px; color: #9aa6ad; }
    .es-foot-c { font-style: italic; white-space: nowrap; } .es-foot-r { white-space: nowrap; text-align: right; max-width: 38%; }
    @media (max-width: 760px) { .es-sheet { padding: 10mm; } }
  `}</style>);
}
window.EstimateSheetStyles = EstimateSheetStyles;

function EstimatePrintStyles() {
  return (<React.Fragment>
    <EstimateSheetStyles />
    <style id="es-print-styles">{`
    .es-proot { position: fixed; inset: 0; z-index: 1300; display: flex; flex-direction: column; }
    .es-pbackdrop { position: absolute; inset: 0; background: rgba(4,18,26,.55); backdrop-filter: blur(2px); }
    .es-ptoolbar { position: relative; z-index: 2; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 20px; background: var(--bg-elev); border-bottom: 1px solid var(--line); }
    .es-ptoolbar-title { font-size: 13.5px; font-weight: 650; color: var(--ink); }
    .es-ptoolbar-actions { display: flex; gap: 12px; align-items: center; }
    .es-pscroll { position: relative; z-index: 1; flex: 1 1 auto; overflow-y: auto; padding: 28px 20px 60px; display: flex; flex-direction: column; align-items: center; gap: 24px; }
    @media print {
      body * { visibility: hidden !important; }
      .es-proot, .es-proot * { visibility: visible !important; }
      .es-proot { position: absolute !important; inset: 0 !important; z-index: 9999; }
      .es-pbackdrop, .es-ptoolbar { display: none !important; }
      .es-pscroll { overflow: visible !important; padding: 0 !important; display: block !important; gap: 0 !important; }
      .es-sheet { box-shadow: none !important; width: auto !important; min-height: 0 !important; padding: 0 !important; margin: 0 !important; }
      .es-sheet + .es-sheet { break-before: page; page-break-before: always; }
      @page { size: A4; margin: 14mm; }
    }
  `}</style>
  </React.Fragment>);
}
