// Quote / request-for-quote module: cart-like queue of products,
// floating button, /quote page with per-product area + contact form.

const QUOTE_STORAGE_KEY = "artifex-quote-items";

function loadQuoteItems() {
  try {
    const raw = localStorage.getItem(QUOTE_STORAGE_KEY);
    const arr = raw ? JSON.parse(raw) : [];
    return Array.isArray(arr) ? arr : [];
  } catch { return []; }
}

function saveQuoteItems(items) {
  localStorage.setItem(QUOTE_STORAGE_KEY, JSON.stringify(items));
  window.dispatchEvent(new Event("artifex:quote"));
}

function useQuote() {
  const [items, setItems] = React.useState(loadQuoteItems);

  React.useEffect(() => {
    const onChange = () => setItems(loadQuoteItems());
    window.addEventListener("artifex:quote", onChange);
    window.addEventListener("storage", onChange);
    return () => {
      window.removeEventListener("artifex:quote", onChange);
      window.removeEventListener("storage", onChange);
    };
  }, []);

  const has = React.useCallback((slug) => items.some(i => i.slug === slug), [items]);

  const add = React.useCallback((slug, area = 0) => {
    const current = loadQuoteItems();
    if (current.some(i => i.slug === slug)) return;
    saveQuoteItems([...current, { slug, area: Number(area) || 0 }]);
  }, []);

  const toggle = React.useCallback((slug, area = 0) => {
    const current = loadQuoteItems();
    const exists = current.some(i => i.slug === slug);
    if (exists) saveQuoteItems(current.filter(i => i.slug !== slug));
    else saveQuoteItems([...current, { slug, area: Number(area) || 0 }]);
  }, []);

  const setArea = React.useCallback((slug, area) => {
    const current = loadQuoteItems();
    saveQuoteItems(current.map(i => i.slug === slug ? { ...i, area: Number(area) || 0 } : i));
  }, []);

  const remove = React.useCallback((slug) => {
    saveQuoteItems(loadQuoteItems().filter(i => i.slug !== slug));
  }, []);

  const clear = React.useCallback(() => saveQuoteItems([]), []);

  return { items, has, add, toggle, setArea, remove, clear };
}

// Parse "120–180 г/м²" or "2.5–3.5 кг/м²" into { min, max, unit, grams }
function parseConsumption(raw) {
  if (!raw) return null;
  const str = String(raw).replace(/\s+/g, " ").trim();
  const m = str.match(/([\d.,]+)\s*[–-]\s*([\d.,]+)\s*(кг|г)/i);
  if (!m) return null;
  const min = parseFloat(m[1].replace(",", "."));
  const max = parseFloat(m[2].replace(",", "."));
  const unit = m[3].toLowerCase();
  if (isNaN(min) || isNaN(max)) return null;
  const factor = unit === "кг" ? 1000 : 1;
  return { min, max, unit, grams: { min: min * factor, max: max * factor } };
}

function formatWeight(grams) {
  if (grams >= 1000) return (grams / 1000).toFixed(grams >= 10000 ? 0 : 1) + " кг";
  return Math.round(grams) + " г";
}

function calcConsumption(product, area) {
  const p = parseConsumption(product.consumption);
  if (!p || !area || area <= 0) return null;
  return {
    min: p.grams.min * area,
    max: p.grams.max * area,
    minText: formatWeight(p.grams.min * area),
    maxText: formatWeight(p.grams.max * area),
    unitRange: `${p.min}–${p.max} ${p.unit}/м²`
  };
}

// ---------- Floating quote button ----------

function FloatingQuoteBtn({ route }) {
  useLang();
  const { items } = useQuote();
  if (items.length === 0) return null;
  if (route === "/quote" || route === "/contacts") return null;
  const label = getLang() === "en"
    ? (items.length === 1 ? "product" : "products")
    : plural(items.length, ["продукт", "продукта", "продуктов"]);
  return (
    <a href="#/quote" className="quote-fab" aria-label={t("quote.fab.ariaOpen")}>
      <span className="quote-fab-icon">📋</span>
      <span className="quote-fab-text">
        <strong>{t("quote.fab.label")}</strong>
        <span>{items.length} {label}</span>
      </span>
      <span className="quote-fab-arrow">→</span>
    </a>
  );
}

function plural(n, forms) {
  const n10 = n % 10, n100 = n % 100;
  if (n10 === 1 && n100 !== 11) return forms[0];
  if (n10 >= 2 && n10 <= 4 && (n100 < 10 || n100 >= 20)) return forms[1];
  return forms[2];
}

// ---------- Quote page ----------

function QuotePage() {
  useLang();
  const quote = useQuote();
  const [sent, setSent] = React.useState(false);
  const [sending, setSending] = React.useState(false);
  const [errMsg, setErrMsg] = React.useState("");
  const [form, setForm] = React.useState({
    name: "",
    phone: "",
    email: "",
    projectType: "residential",
    area: "",
    timeline: "month",
    message: ""
  });

  const queuedProducts = quote.items.map(it => {
    const p = PRODUCTS.find(pp => pp.slug === it.slug);
    return p ? { ...p, area: it.area } : null;
  }).filter(Boolean);

  const totals = queuedProducts.reduce((acc, p) => {
    const c = calcConsumption(p, p.area);
    if (c) { acc.min += c.min; acc.max += c.max; }
    return acc;
  }, { min: 0, max: 0 });

  const submit = async (e) => {
    e.preventDefault();
    setErrMsg("");
    const validation = _validateContactForm(form);
    if (!validation.ok) {
      setErrMsg(validation.message || t("form.errNamePhone"));
      return;
    }
    if (!_canSubmitNow()) {
      setErrMsg(t("form.errRateLimited") || "Слишком много заявок подряд — подождите немного.");
      return;
    }
    setSending(true);
    try {
      await sendRequest({
        source: "quote",
        contact: validation.cleaned,
        items: queuedProducts.map(p => ({ slug: p.slug, name: p.name, area: p.area }))
      });
      _recordSubmit();
      quote.clear();
      setSent(true);
    } catch (err) {
      setErrMsg(t("form.errSendRetry"));
    } finally {
      setSending(false);
    }
  };

  if (sent) {
    return (
      <main className="quote-page">
        <div className="quote-success">
          <div className="success-mark">✓</div>
          <h1>{t("quote.success.title")}</h1>
          <p>{t("quote.success.body1")}<br/>
            {t("quote.success.body2")}</p>
          <div className="quote-success-actions">
            <Link to="/catalog" className="btn btn-primary">{t("quote.success.continue")}</Link>
            <Link to="/" className="btn btn-ghost">{t("quote.success.home")}</Link>
          </div>
        </div>
      </main>
    );
  }

  return (
    <main className="quote-page">
      <section className="page-hero">
        <div className="eyebrow">{t("quote.eyebrow")}</div>
        <h1 className="page-title">{t("quote.title")}<br/><em>{t("quote.titleItalic")}</em></h1>
        <p className="page-lede">{t("quote.lede")}</p>
      </section>

      <section className="quote-grid">
        <div className="quote-items">
          <div className="quote-items-head">
            <h2 className="section-title">{t("quote.items.title")}</h2>
            {queuedProducts.length > 0 && (
              <button className="link-arrow" onClick={quote.clear}>{t("quote.items.clear")}</button>
            )}
          </div>
          {queuedProducts.length === 0 ? (
            <div className="quote-empty">
              <p>{t("quote.items.empty")}</p>
              <Link to="/catalog" className="btn btn-primary">{t("quote.items.openCatalog")}</Link>
            </div>
          ) : (
            <div className="quote-list">
              {queuedProducts.map(p => {
                const calc = calcConsumption(p, p.area);
                return (
                  <div key={p.slug} className="quote-item">
                    <Link to={`/product/${p.slug}`} className="quote-item-swatch">
                      <Swatch product={p}/>
                    </Link>
                    <div className="quote-item-body">
                      <div className="quote-item-head">
                        <Link to={`/product/${p.slug}`} className="quote-item-name">{p.name}</Link>
                        <button className="quote-item-remove" onClick={() => quote.remove(p.slug)} aria-label={t("remove")}>×</button>
                      </div>
                      <div className="quote-item-effect">{p.effect}</div>
                      <div className="quote-item-area">
                        <label>
                          <span>{t("quote.item.area")}</span>
                          <input
                            type="number"
                            min="0"
                            step="0.5"
                            value={p.area || ""}
                            onChange={e => quote.setArea(p.slug, e.target.value)}
                            placeholder="0"
                          />
                        </label>
                        <div className="quote-item-calc">
                          {calc ? (
                            <>
                              <span className="quote-item-calc-label">{t("quote.item.calcLabel")}</span>
                              <strong>{calc.minText} – {calc.maxText}</strong>
                              <span className="quote-item-calc-rate">({calc.unitRange})</span>
                            </>
                          ) : (
                            <span style={{ color: "var(--ink-2)", opacity: 0.7, fontSize: 13 }}>{t("quote.item.calcEmpty")}</span>
                          )}
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}
              {totals.max > 0 && (
                <div className="quote-total">
                  <span>{t("quote.total")}</span>
                  <strong>{formatWeight(totals.min)} – {formatWeight(totals.max)}</strong>
                </div>
              )}
            </div>
          )}
        </div>

        <aside className="quote-form">
          <h2 className="section-title">{t("quote.contactData")}</h2>
          <form onSubmit={submit}>
            <label>
              <span>{t("form.name")}</span>
              <input required value={form.name} onChange={e => setForm({...form, name: e.target.value})}/>
            </label>
            <div className="form-row">
              <label>
                <span>{t("form.phone")}</span>
                <input required type="tel" value={form.phone} onChange={e => setForm({...form, phone: e.target.value})} placeholder="+998 ..."/>
              </label>
              <label>
                <span>{t("form.emailOpt")}</span>
                <input type="email" value={form.email} onChange={e => setForm({...form, email: e.target.value})}/>
              </label>
            </div>
            <div className="form-row">
              <label>
                <span>{t("form.projectType")}</span>
                <select value={form.projectType} onChange={e => setForm({...form, projectType: e.target.value})}>
                  <option value="residential">{t("form.projectType.residential")}</option>
                  <option value="facade">{t("form.projectType.facade")}</option>
                  <option value="horeca">{t("form.projectType.horeca")}</option>
                  <option value="office">{t("form.projectType.office")}</option>
                  <option value="retail">{t("form.projectType.retail")}</option>
                  <option value="public">{t("form.projectType.public")}</option>
                  <option value="other">{t("form.projectType.other")}</option>
                </select>
              </label>
              <label>
                <span>{t("quote.timeline")}</span>
                <select value={form.timeline} onChange={e => setForm({...form, timeline: e.target.value})}>
                  <option value="asap">{t("quote.timeline.asap")}</option>
                  <option value="week">{t("quote.timeline.week")}</option>
                  <option value="month">{t("quote.timeline.month")}</option>
                  <option value="quarter">{t("quote.timeline.quarter")}</option>
                  <option value="planning">{t("quote.timeline.planning")}</option>
                </select>
              </label>
            </div>
            <label>
              <span>{t("quote.totalArea")}</span>
              <input type="number" min="0" value={form.area} onChange={e => setForm({...form, area: e.target.value})} placeholder={t("quote.totalAreaPlaceholder")}/>
            </label>
            <label>
              <span>{t("form.commentLabel")}</span>
              <textarea rows="3" value={form.message} onChange={e => setForm({...form, message: e.target.value})} placeholder={t("form.commentPlaceholder")}/>
            </label>
            {errMsg && <div className="form-err">{errMsg}</div>}
            <button type="submit" className="btn btn-primary" disabled={sending || queuedProducts.length === 0}>
              {sending ? t("form.sending") : t("form.submitQuote")}
            </button>
            <p className="form-note">
              {t("quote.note")}
              {queuedProducts.length === 0 && <><br/>{t("quote.addHint1")} <Link to="/catalog">{t("quote.addHint2")}</Link>.</>}
            </p>
          </form>
        </aside>
      </section>
    </main>
  );
}

// ---------- Validation ----------
// Client-side only — the form POSTs to a third-party endpoint (Formspree
// etc.) which performs the canonical validation. This is the first line of
// defence: trim, cap field lengths, sanity-check email/phone, strip null
// bytes / control chars that some downstream tools mishandle.
const _MAX = { name: 120, phone: 40, email: 160, message: 2000, area: 12 };
function _stripCtrl(s) {
  return String(s == null ? "" : s).replace(/[\u0000-\u001f]/g, "").trim();
}
function _validateContactForm(form) {
  const cleaned = {};
  for (const k of Object.keys(form || {})) {
    cleaned[k] = _stripCtrl(form[k]);
    if (_MAX[k] != null && cleaned[k].length > _MAX[k]) {
      cleaned[k] = cleaned[k].slice(0, _MAX[k]);
    }
  }
  if (!cleaned.name || !cleaned.phone) return { ok: false, message: t("form.errNamePhone") };
  // Phone: digits and a few separators, 7–20 chars (E.164 fits).
  if (!/^[+\d][\d\s().\-]{6,19}$/.test(cleaned.phone)) {
    return { ok: false, message: t("form.errPhone") || "Введите корректный телефон" };
  }
  // Email is optional, but if present it must look like an email.
  if (cleaned.email && !/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(cleaned.email)) {
    return { ok: false, message: t("form.errEmail") || "Введите корректный email" };
  }
  return { ok: true, cleaned };
}

// ---------- Client-side rate limit (defence-in-depth) ----------
// Forms POST to a third-party endpoint, so this prevents accidental
// double-submits and trivial flooding from a single browser. Real abuse
// must be stopped at the endpoint (Formspree honeypot, server reCAPTCHA, etc).
const _RL_KEY = "artifex-form-rl-v1";
const _RL_WINDOW_MS = 60 * 60 * 1000;     // 1 hour rolling window
const _RL_MAX_PER_WINDOW = 5;
const _RL_MIN_GAP_MS = 4000;              // no submit faster than 4s after the last
function _readRl() {
  try { return JSON.parse(localStorage.getItem(_RL_KEY) || "[]"); } catch { return []; }
}
function _canSubmitNow() {
  const now = Date.now();
  const log = _readRl().filter(t => now - t < _RL_WINDOW_MS);
  if (log.length && now - log[log.length - 1] < _RL_MIN_GAP_MS) return false;
  if (log.length >= _RL_MAX_PER_WINDOW) return false;
  return true;
}
function _recordSubmit() {
  const now = Date.now();
  const log = _readRl().filter(t => now - t < _RL_WINDOW_MS);
  log.push(now);
  try { localStorage.setItem(_RL_KEY, JSON.stringify(log)); } catch {}
}

// ---------- Request submission ----------

async function sendRequest(payload) {
  const endpoint = (COMPANY && COMPANY.formEndpoint) || "";
  if (!endpoint) {
    // No endpoint configured — emulate success so the UI flows
    console.log("[artifex] form submission (no endpoint configured):", payload);
    await new Promise(r => setTimeout(r, 400));
    return { ok: true, simulated: true };
  }
  const res = await fetch(endpoint, {
    method: "POST",
    headers: { "Content-Type": "application/json", "Accept": "application/json" },
    body: JSON.stringify({ ...payload, ts: new Date().toISOString() })
  });
  if (!res.ok) throw new Error("HTTP " + res.status);
  return res.json().catch(() => ({ ok: true }));
}

// ---------- Add-to-quote toggle button ----------

function QuoteToggleBtn({ product, className = "", full = false }) {
  useLang();
  const quote = useQuote();
  const active = quote.has(product.slug);
  const onClick = (e) => {
    e.preventDefault();
    e.stopPropagation();
    quote.toggle(product.slug);
  };
  return (
    <button
      type="button"
      className={`quote-toggle ${active ? "active" : ""} ${className}`}
      onClick={onClick}
      aria-pressed={active}
      title={active ? t("quote.toggle.remove") : t("quote.toggle.add")}>
      {active ? "✓" : "+"}
      {full && <span>{active ? t("quote.toggle.inQuote") : t("quote.toggle.toAdd")}</span>}
    </button>
  );
}

Object.assign(window, {
  useQuote, QuotePage, FloatingQuoteBtn, QuoteToggleBtn,
  parseConsumption, calcConsumption, formatWeight, plural, sendRequest
});
