// MDM SORP — shared primitives (FieldBadge, StatusChip, Icon, Toast, etc.)
const { useState, useEffect, useRef, useMemo, useCallback, createContext, useContext } = React;

/* ------------ I18N hook ------------ */
const I18nCtx = createContext({ lang: "ru", t: (k) => k });
const useI18n = () => useContext(I18nCtx);

function I18nProvider({ children }) {
  const [lang, setLang] = useState(() => localStorage.getItem("sorp-lang") || "ru");
  useEffect(() => { localStorage.setItem("sorp-lang", lang); document.documentElement.lang = lang; }, [lang]);
  const t = useCallback((key) => (window.I18N[lang] && window.I18N[lang][key]) || window.I18N.ru[key] || key, [lang]);
  return <I18nCtx.Provider value={{ lang, setLang, t }}>{children}</I18nCtx.Provider>;
}

/* ------------ Lucide-style inline SVG icons (1.5px stroke) ------------ */
const Icon = ({ name, size = 16, className = "" }) => {
  const paths = {
    home: <><path d="M3 11l9-8 9 8"/><path d="M5 9v12h14V9"/></>,
    deals: <><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/><path d="M8 5V3"/><path d="M16 5V3"/></>,
    parties: <><circle cx="9" cy="8" r="3"/><path d="M3 20c0-3.3 2.7-6 6-6s6 2.7 6 6"/><circle cx="17" cy="9" r="2.5"/><path d="M14 20c0-2.5 2-4.5 4.5-4.5s2.5 1.5 2.5 4.5"/></>,
    box: <><path d="M3 7l9-4 9 4v10l-9 4-9-4z"/><path d="M3 7l9 4 9-4"/><path d="M12 11v10"/></>,
    grid: <><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></>,
    docs: <><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6"/></>,
    queue: <><path d="M3 6h18"/><path d="M3 12h18"/><path d="M3 18h12"/></>,
    merge: <><path d="M8 3v6c0 3 4 3 4 6v6"/><path d="M16 3v6c0 3-4 3-4 6"/></>,
    upload: <><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5"/><path d="M12 3v12"/></>,
    shield: <><path d="M12 3l8 3v6c0 5-3.5 8.5-8 9-4.5-.5-8-4-8-9V6z"/></>,
    bar: <><path d="M3 3v18h18"/><rect x="7" y="11" width="3" height="6"/><rect x="12" y="7" width="3" height="10"/><rect x="17" y="14" width="3" height="3"/></>,
    cog: <><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h0a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></>,
    plug: <><path d="M9 2v6"/><path d="M15 2v6"/><path d="M5 10h14v3a7 7 0 0 1-14 0z"/><path d="M12 20v2"/></>,
    book: <><path d="M4 19.5V4a2 2 0 0 1 2-2h14v18H6a2 2 0 0 0-2 2"/><path d="M20 22H6a2 2 0 0 1-2-2"/></>,
    search: <><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></>,
    bell: <><path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></>,
    plus: <><path d="M12 5v14M5 12h14"/></>,
    minus: <><path d="M5 12h14"/></>,
    check: <><path d="M5 12l5 5L20 7"/></>,
    x: <><path d="M18 6 6 18M6 6l12 12"/></>,
    arrow_right: <><path d="M5 12h14M13 5l7 7-7 7"/></>,
    arrow_up_right: <><path d="M7 17 17 7"/><path d="M7 7h10v10"/></>,
    chevron_right: <><path d="m9 5 7 7-7 7"/></>,
    chevron_down: <><path d="m5 9 7 7 7-7"/></>,
    filter: <><path d="M22 3H2l8 9.5V19l4 2v-8.5z"/></>,
    sort: <><path d="M3 6h18"/><path d="M6 12h12"/><path d="M10 18h4"/></>,
    download: <><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><path d="M12 15V3"/></>,
    eye: <><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></>,
    sparkle: <><path d="M12 3v4M12 17v4M3 12h4M17 12h4"/><path d="M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M5.6 18.4l2.8-2.8M15.6 8.4l2.8-2.8"/></>,
    link: <><path d="M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07L11.59 4.34"/><path d="M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1.41-1.41"/></>,
    undo: <><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-15-6.7L3 13"/></>,
    history: <><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l3 2"/></>,
    pencil: <><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/></>,
    copy: <><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></>,
    more: <><circle cx="5" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/></>,
    columns: <><rect x="3" y="3" width="7" height="18" rx="1"/><rect x="14" y="3" width="7" height="18" rx="1"/></>,
    flag: <><path d="M4 22V4a2 2 0 0 1 2-2h11l-2 5 2 5H6"/></>,
    alert: <><path d="M12 3l10 18H2z"/><path d="M12 10v5"/><path d="M12 18v0"/></>,
    lightbulb: <><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 12.7c.7.6 1 1.4 1 2.3v1h6v-1c0-.9.3-1.7 1-2.3A7 7 0 0 0 12 2z"/></>,
    list: <><path d="M3 6h18M3 12h18M3 18h18"/></>,
    bookmark: <><path d="M6 3h12v18l-6-4-6 4z"/></>,
    star: <><path d="m12 2 3 7h7l-5.5 4.5L18 21l-6-4-6 4 1.5-7.5L2 9h7z"/></>,
    info: <><circle cx="12" cy="12" r="10"/><path d="M12 8v0"/><path d="M11 12h1v5"/></>,
    file: <><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></>,
    image: <><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-5-5L5 21"/></>,
    table: <><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M3 15h18M9 3v18M15 3v18"/></>,
    kanban: <><rect x="3" y="3" width="5" height="18" rx="1"/><rect x="10" y="3" width="5" height="12" rx="1"/><rect x="17" y="3" width="4" height="8" rx="1"/></>,
    gallery: <><rect x="3" y="3" width="8" height="8" rx="1"/><rect x="13" y="3" width="8" height="8" rx="1"/><rect x="3" y="13" width="8" height="8" rx="1"/><rect x="13" y="13" width="8" height="8" rx="1"/></>,
    calendar: <><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18"/><path d="M8 3v4"/><path d="M16 3v4"/></>,
    timeline: <><path d="M3 7h18"/><path d="M3 12h12"/><path d="M3 17h7"/><circle cx="3" cy="7" r="1"/><circle cx="3" cy="12" r="1"/><circle cx="3" cy="17" r="1"/></>,
    group: <><path d="M3 6h7"/><path d="M3 12h11"/><path d="M3 18h7"/><path d="M14 4v16"/><path d="M14 12l4-2"/><path d="M14 12l4 2"/></>,
    palette: <><circle cx="13.5" cy="6.5" r="1.5"/><circle cx="17.5" cy="10.5" r="1.5"/><circle cx="8.5" cy="7.5" r="1.5"/><circle cx="6.5" cy="12.5" r="1.5"/><path d="M12 2a10 10 0 1 0 10 10c0-1.7-1.4-3-3-3h-2c-1.7 0-3-1.3-3-3 0-1.7 1.3-3 3-3a10 10 0 0 0-5-1z"/></>,
    rows: <><rect x="3" y="4" width="18" height="4" rx="1"/><rect x="3" y="10" width="18" height="4" rx="1"/><rect x="3" y="16" width="18" height="4" rx="1"/></>,
  };
  const p = paths[name] || paths.info;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" className={"ic " + className} aria-hidden="true">
      {p}
    </svg>
  );
};

/* ------------ FieldBadge ------------ */
const FieldBadge = ({ src = "ai", conf = 0.9, raw, when, applied }) => {
  const meta = window.SRC_META[src] || window.SRC_META.manual;
  const tone = conf < 0.5 ? "bad" : conf < 0.8 ? "warn" : "ok";
  const pct = Math.round(conf * 100);
  return (
    <span className={"fbadge " + meta.color + " " + tone}>
      <span className="src">{meta.label}</span>
      <span className="conf" style={{ "--c": pct + "%" }} />
      <span>{pct}</span>
      <span className="fb-tip">
        <div className="row"><span className="k">Источник</span><span className="v">{meta.label}</span></div>
        <div className="row"><span className="k">Уверенность</span><span className="v">{pct}%</span></div>
        {raw !== undefined && <div className="row"><span className="k">Raw</span><span className="v mono">{raw || "—"}</span></div>}
        {when && <div className="row"><span className="k">Когда</span><span className="v">{when}</span></div>}
        {applied && <div className="row"><span className="k">Применено</span><span className="v">{applied}</span></div>}
      </span>
    </span>
  );
};

/* ------------ Chip / Status ------------ */
const Chip = ({ tone = "default", children, dot = false }) => (
  <span className={"chip " + (tone === "default" ? "" : tone)}>
    {dot && <span className="chip-dot" />}
    {children}
  </span>
);

const RoleChip = ({ role }) => {
  const map = {
    customer:   { tone: "danger",  label: "Заказчик",   label_en: "Customer" },
    supplier:   { tone: "info",    label: "Поставщик",  label_en: "Supplier" },
    end_user:   { tone: "warning", label: "Конечник",   label_en: "End user" },
    vehicle:    { tone: "ink",     label: "Заход",      label_en: "Vehicle" },
    beneficiary:{ tone: "outline", label: "Бенефициар", label_en: "Beneficiary" },
    contact:    { tone: "outline", label: "Контакт",    label_en: "Contact" },
    employee:   { tone: "outline", label: "Сотрудник",  label_en: "Employee" },
  };
  const { lang } = useI18n();
  const m = map[role] || { tone: "outline", label: role, label_en: role };
  return <Chip tone={m.tone}>{lang === "en" ? m.label_en : m.label}</Chip>;
};

const SanctionsChip = ({ status }) => {
  if (status === "flag")   return <Chip tone="danger" dot><Icon name="shield" size={11}/> Санкции</Chip>;
  if (status === "review") return <Chip tone="warning" dot>На проверке</Chip>;
  if (status === "match")  return <Chip tone="warning" dot>Совпадение</Chip>;
  if (status === "clean")  return <Chip tone="success">Чисто</Chip>;
  return <Chip tone="outline">—</Chip>;
};

/* ------------ Avatar ------------ */
const Avatar = ({ name = "", size = 26, color }) => {
  const initials = name.split(/\s+/).map(s => s[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
  const palette = ["#D63D4A", "#2C5C8C", "#2F7D5B", "#C77A1F", "#6E45E2", "#3A4049"];
  const i = (name.charCodeAt(0) || 0) % palette.length;
  return (
    <span style={{
      width: size, height: size, borderRadius: 999,
      background: color || palette[i],
      color: "#fff", display: "inline-flex",
      alignItems: "center", justifyContent: "center",
      fontWeight: 700, fontSize: Math.floor(size * 0.42),
      flexShrink: 0,
    }}>{initials || "?"}</span>
  );
};

/* ------------ Flag (country) ------------ */
const Flag = ({ code }) => {
  const c = (code || "").toLowerCase();
  if (!["ru", "en", "cn", "ae", "de", "tr"].includes(c)) return <span className="muted">—</span>;
  const map = { tr: "linear-gradient(to bottom, #E30A17 50%, #fff 50%)" };
  return <span className={"flag-" + c} style={map[c] ? { background: map[c] } : undefined} title={code}></span>;
};

/* ------------ Toast (with Undo) ------------ */
const ToastCtx = createContext(() => {});
const useToast = () => useContext(ToastCtx);

function ToastHost({ children }) {
  const [list, setList] = useState([]);
  const push = useCallback((msg, opts = {}) => {
    const id = Math.random().toString(36).slice(2);
    setList(l => [...l, { id, msg, ...opts }]);
    setTimeout(() => setList(l => l.filter(t => t.id !== id)), opts.duration || 4000);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div className="toast-stack">
        {list.map(t => (
          <div className="toast" key={t.id}>
            <Icon name={t.icon || "check"} size={14}/>
            <span>{t.msg}</span>
            {t.onUndo && <button className="undo" onClick={() => { t.onUndo(); setList(l => l.filter(x => x.id !== t.id)); }}>Отменить</button>}
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}

/* ------------ Drawer ------------ */
const Drawer = ({ open, onClose, children, width = 540 }) => {
  if (!open) return null;
  return (
    <>
      <div className="drawer-backdrop" onClick={onClose} />
      <div className="drawer" style={{ width }}>
        {children}
      </div>
    </>
  );
};

/* ------------ Command palette ------------ */
function CommandPalette({ open, onClose, navigate }) {
  const { t } = useI18n();
  const [q, setQ] = useState("");
  const [active, setActive] = useState(0);
  useEffect(() => { setQ(""); setActive(0); }, [open]);

  const all = useMemo(() => {
    const deals = window.DATA.deals.map(d => ({
      section: "cp_entities", icon: "deals",
      label: d.id + " · " + d.title, sub: d.stage,
      action: () => navigate("deal", { id: d.id })
    }));
    const parties = window.DATA.parties.slice(0, 8).map(p => ({
      section: "cp_entities", icon: "parties",
      label: p.short + " — " + p.full, sub: p.country,
      action: () => navigate("party", { id: p.id })
    }));
    const actions = [
      { section: "cp_actions", icon: "plus",    label: t("cp_create_deal"),     sub: "⏎", action: () => navigate("deal", { id: "SORP-3974" }) },
      { section: "cp_actions", icon: "plus",    label: t("cp_create_supplier"), sub: "⏎", action: () => navigate("parties") },
      { section: "cp_actions", icon: "upload",  label: t("cp_open_import"),     sub: "⏎", action: () => navigate("import") },
      { section: "cp_actions", icon: "shield",  label: t("cp_run_sanctions"),   sub: "⏎", action: () => navigate("sanctions") },
    ];
    return [...actions, ...deals, ...parties];
  }, [navigate, t]);

  const filtered = useMemo(() => {
    const s = q.trim().toLowerCase();
    if (!s) return all.slice(0, 10);
    return all.filter(x => x.label.toLowerCase().includes(s) || (x.sub || "").toLowerCase().includes(s)).slice(0, 10);
  }, [q, all]);

  const onKey = (e) => {
    if (e.key === "Escape") onClose();
    else if (e.key === "ArrowDown") { e.preventDefault(); setActive(a => Math.min(filtered.length - 1, a + 1)); }
    else if (e.key === "ArrowUp")   { e.preventDefault(); setActive(a => Math.max(0, a - 1)); }
    else if (e.key === "Enter")     { e.preventDefault(); const r = filtered[active]; if (r) { r.action(); onClose(); } }
  };

  if (!open) return null;
  let lastSection = null;
  return (
    <div className="cp-backdrop" onClick={onClose}>
      <div className="cp" onClick={(e) => e.stopPropagation()}>
        <input autoFocus value={q} onChange={(e) => { setQ(e.target.value); setActive(0); }} onKeyDown={onKey} placeholder={t("search")} />
        <div className="cp-list">
          {filtered.map((r, i) => {
            const showSection = r.section !== lastSection;
            lastSection = r.section;
            return (
              <React.Fragment key={i}>
                {showSection && <div className="cp-section">{t(r.section)}</div>}
                <div className={"cp-row " + (i === active ? "active" : "")} onMouseEnter={() => setActive(i)} onClick={() => { r.action(); onClose(); }}>
                  <Icon name={r.icon} size={14}/>
                  <span>{r.label}</span>
                  <span className="sub">{r.sub}</span>
                </div>
              </React.Fragment>
            );
          })}
          {filtered.length === 0 && <div className="cp-row muted">Нет совпадений</div>}
        </div>
      </div>
    </div>
  );
}

/* ------------ Money formatting ------------ */
const fmtMoney = (n, ccy = "USD") => {
  if (n == null) return "—";
  const sym = { USD: "$", EUR: "€", AED: "AED ", RUB: "₽", CNY: "¥" }[ccy] || (ccy + " ");
  const num = n.toLocaleString("ru-RU", { maximumFractionDigits: 0 });
  return ccy === "RUB" ? num + " ₽" : sym + num;
};

/* expose for other scripts */
Object.assign(window, {
  I18nProvider, useI18n, I18nCtx,
  Icon, FieldBadge, Chip, RoleChip, SanctionsChip, Avatar, Flag,
  ToastHost, useToast, Drawer, CommandPalette, fmtMoney,
});
