/* Kay Construction — shared UI primitives, hooks, icons.
   Exposes components on window for other babel scripts. */

const { useState, useEffect, useRef, useMemo, useCallback } = React;
const S = window.KayStore;
const I = window.KayI18n;
const t = (k) => I.t(k);
const tStatus = (s) => I.tStatus(s);

/* re-render hook: subscribes to data + language changes */
function useStore() {
  const [, force] = useState(0);
  useEffect(() => {
    const a = S.subscribe(() => force((n) => n + 1));
    const b = I.subscribe(() => force((n) => n + 1));
    return () => { a(); b(); };
  }, []);
  return S;
}
function useLang() {
  const [lang, setLang] = useState(I.getLang());
  useEffect(() => I.subscribe((l) => setLang(l)), []);
  return [lang, I.setLang];
}

/* ---------------- icons (stroke, 1.6, currentColor) ---------------- */
const ICONS = {
  dashboard: "M3 3h7v8H3V3Zm0 11h7v7H3v-7Zm11-11h7v7h-7V3Zm0 11h7v7h-7v-7Z",
  projects: "M3 21h18M5 21V7l8-4v18M19 21V11l-6-3M9 9v.01M9 13v.01M9 17v.01",
  clients: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm13 10v-2a4 4 0 0 0-3-3.87M16 3.13A4 4 0 0 1 16 11",
  doc: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Zm0 0v6h6",
  rab: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01",
  quotation: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6Zm0 0v6h6M9 13h6M9 17h4",
  spk: "M9 4h6a1 1 0 0 1 1 1v1h2a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h2V5a1 1 0 0 1 1-1Zm0 2h6M9 13l2 2 4-4",
  invoice: "M5 3h14v18l-3-2-2 2-2-2-2 2-2-2-3 2V3Zm3 6h8M8 13h8M8 17h5",
  kwitansi: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-4-10 3 3 5-5",
  expenses: "M3 7h18v12H3V7Zm0 0 3-4h12l3 4M16 13h2M7 11h5",
  settings: "M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm7.4-3a7.4 7.4 0 0 0-.1-1.2l2-1.5-2-3.5-2.4 1a7 7 0 0 0-2-1.2l-.4-2.6h-4l-.4 2.6a7 7 0 0 0-2 1.2l-2.4-1-2 3.5 2 1.5a7.4 7.4 0 0 0 0 2.4l-2 1.5 2 3.5 2.4-1a7 7 0 0 0 2 1.2l.4 2.6h4l.4-2.6a7 7 0 0 0 2-1.2l2.4 1 2-3.5-2-1.5c.06-.4.1-.8.1-1.2Z",
  plus: "M12 5v14M5 12h14",
  search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm10 2-4.3-4.3",
  edit: "M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5Z",
  trash: "M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2m2 0v14a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V6h12ZM10 11v6M14 11v6",
  close: "M18 6 6 18M6 6l12 12",
  chevR: "M9 6l6 6-6 6",
  chevL: "M15 6l-6 6 6 6",
  chevD: "M6 9l6 6 6-6",
  print: "M6 9V3h12v6M6 18H4a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-2M6 14h12v7H6v-7Z",
  download: "M12 3v12m0 0 4-4m-4 4-4-4M4 17v2a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-2",
  back: "M19 12H5m0 0 6 6m-6-6 6-6",
  check: "M20 6 9 17l-5-5",
  calendar: "M8 2v4M16 2v4M3 9h18M5 5h14a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Z",
  dots: "M12 13a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm0-6a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm0 12a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z",
  building: "M3 21h18M6 21V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v16M10 9h.01M14 9h.01M10 13h.01M14 13h.01M10 17h.01M14 17h.01",
  copy: "M9 9h10a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V10a1 1 0 0 1 1-1Zm-2 0V5a1 1 0 0 1 1-1h10",
  arrow: "M5 12h14m0 0-6-6m6 6-6 6",
  user: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z",
  flag: "M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1v12ZM4 22v-7",
  menu: "M3 12h18M3 6h18M3 18h18",
  wand: "M15 4V2m0 14v-2M8 9h2m10 0h2M4 20l13-13M11 6 8 9m11 5-3-3",
  clock: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-15v5l3 2",
  report: "M3 3v18h18M7 14l3-3 3 3 5-6M7 14v4M11 11v7M14 14v4M18 8v10",
  tag: "M20.6 13.4 12 22l-9-9V4a1 1 0 0 1 1-1h9l8.6 8.6a1.4 1.4 0 0 1 0 2.8ZM7.5 7.5h.01",
  swap: "M7 4v13m0 0-3-3m3 3 3-3M17 20V7m0 0 3 3m-3-3-3 3"
};
function Icon({ name, size = 18, className = "", style }) {
  const d = ICONS[name];
  if (!d) return null;
  return (
    <svg className={className} width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" style={style}>
      {d.split("M").filter(Boolean).map((seg, i) => <path key={i} d={"M" + seg} />)}
    </svg>
  );
}

/* ---------------- buttons ---------------- */
function Button({ children, variant, size, icon, onClick, type, disabled, title, style }) {
  const cls = ["btn", variant || "", size === "sm" ? "sm" : ""].filter(Boolean).join(" ");
  return (
    <button className={cls} onClick={onClick} type={type || "button"} disabled={disabled} title={title} style={style}>
      {icon && <Icon name={icon} size={size === "sm" ? 14 : 15} />}
      {children}
    </button>
  );
}

/* ---------------- badges ---------------- */
const STATUS_TONE = {
  prospek: "neutral", penawaran: "info", berjalan: "info", selesai: "pos", dibatalkan: "neg",
  draft: "neutral", final: "warn", disetujui: "pos", terkirim: "info", ditolak: "neg", kadaluarsa: "neutral",
  aktif: "info", lunas: "pos", "lunas sebagian": "warn", "jatuh tempo": "neg"
};
function StatusBadge({ status }) {
  const tone = STATUS_TONE[status] || "neutral";
  return <span className={"badge " + tone}><span className="dot"></span>{tStatus(status)}</span>;
}
function Badge({ children, tone }) { return <span className={"badge " + (tone || "neutral")}>{children}</span>; }

/* ---------------- progress / meter ---------------- */
function Progress({ value }) {
  const v = Math.max(0, Math.min(100, value || 0));
  return <div className="progress"><span style={{ width: v + "%" }}></span></div>;
}

/* ---------------- forms ---------------- */
function Field({ label, optional, children, full, hint }) {
  return (
    <div className={"field" + (full ? " full" : "")}>
      {label && <label>{label} {optional && <span className="opt">· {t("common.optional")}</span>}</label>}
      {children}
      {hint && <div className="tiny muted">{hint}</div>}
    </div>
  );
}
function Input(props) { return <input className={"input " + (props.numeric ? "num" : "")} {...stripCustom(props)} />; }
function Textarea(props) { return <textarea className="input" {...stripCustom(props)} />; }
function Select({ children, ...props }) { return <select className="select" {...stripCustom(props)}>{children}</select>; }
function stripCustom(p) { const { numeric, ...rest } = p; return rest; }

/* money input — shows Rp prefix, edits raw number */
function MoneyInput({ value, onChange, placeholder }) {
  return (
    <div className="input-prefix">
      <span>Rp</span>
      <input className="input num" type="text" inputMode="numeric"
        value={value ? S.formatNumber(value) : ""}
        placeholder={placeholder || "0"}
        onChange={(e) => {
          const raw = e.target.value.replace(/[^0-9]/g, "");
          onChange(raw ? parseInt(raw, 10) : 0);
        }} />
    </div>
  );
}

/* segmented control */
function Segmented({ value, onChange, options }) {
  return (
    <div className="segmented">
      {options.map((o) => (
        <button key={o.value} className={value === o.value ? "on" : ""} onClick={() => onChange(o.value)}>{o.label}</button>
      ))}
    </div>
  );
}

/* language toggle for a document */
function DocLangToggle({ value, onChange }) {
  return <Segmented value={value} onChange={onChange} options={[{ value: "id", label: "ID" }, { value: "en", label: "EN" }]} />;
}

/* ---------------- modal ---------------- */
function Modal({ title, children, onClose, size, footer }) {
  useEffect(() => {
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, [onClose]);
  return (
    <div className="overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className={"modal " + (size || "")} onMouseDown={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <div className="modal-title">{title}</div>
          <Button variant="ghost" size="sm" icon="close" onClick={onClose} />
        </div>
        <div className="modal-body">{children}</div>
        {footer && <div className="modal-foot">{footer}</div>}
      </div>
    </div>
  );
}

/* confirm helper */
function useConfirm() {
  const [state, setState] = useState(null);
  const confirm = (msg, onYes) => setState({ msg, onYes });
  const node = state ? (
    <Modal title={t("common.delete")} size="" onClose={() => setState(null)}
      footer={<>
        <Button variant="ghost" onClick={() => setState(null)}>{t("common.cancel")}</Button>
        <Button variant="danger" onClick={() => { state.onYes(); setState(null); }}>{t("common.delete")}</Button>
      </>}>
      <p style={{ margin: 0, color: "var(--ink-soft)" }}>{state.msg}</p>
    </Modal>
  ) : null;
  return [confirm, node];
}

/* ---------------- empty state ---------------- */
function Empty({ icon, title, sub, action }) {
  return (
    <div className="empty">
      <Icon name={icon || "doc"} size={40} className="ic" />
      <div className="t">{title || t("common.empty")}</div>
      {sub && <div style={{ marginBottom: action ? 16 : 0 }}>{sub}</div>}
      {action}
    </div>
  );
}

/* page header */
function PageHead({ title, sub, children }) {
  return (
    <div className="page-head">
      <div>
        <h1 className="page-title">{title}</h1>
        {sub && <div className="page-sub">{sub}</div>}
      </div>
      {children && <div className="row" style={{ gap: 10 }}>{children}</div>}
    </div>
  );
}

/* navigate helper (hash router) */
function go(path) { window.location.hash = path; }

/* read an image File, downscale to maxDim, return dataURL via callback (keeps localStorage small) */
function imageFileToDataURL(file, maxDim, cb) {
  if (!file) return;
  const reader = new FileReader();
  reader.onload = (e) => {
    const img = new Image();
    img.onload = () => {
      let { width, height } = img;
      const m = maxDim || 1400;
      if (width > m || height > m) { const s = m / Math.max(width, height); width = Math.round(width * s); height = Math.round(height * s); }
      const cv = document.createElement("canvas");
      cv.width = width; cv.height = height;
      const ctx = cv.getContext("2d");
      ctx.drawImage(img, 0, 0, width, height);
      const isPng = /png/i.test(file.type);
      cb(cv.toDataURL(isPng ? "image/png" : "image/jpeg", isPng ? undefined : 0.82));
    };
    img.src = e.target.result;
  };
  reader.readAsDataURL(file);
}

/* hidden-input image picker button */
function ImagePicker({ label, icon, capture, accept, maxDim, onPick, size }) {
  const ref = useRef(null);
  return (
    <>
      <input ref={ref} type="file" accept={accept || "image/*"} capture={capture || undefined} style={{ display: "none" }}
        onChange={(e) => { const f = e.target.files && e.target.files[0]; if (f) imageFileToDataURL(f, maxDim, onPick); e.target.value = ""; }} />
      <Button size={size} icon={icon || "download"} onClick={() => ref.current && ref.current.click()}>{label}</Button>
    </>
  );
}

/* money display with sign coloring */
function Money({ value, sign, bold }) {
  const neg = value < 0;
  return <span className={"tnum" + (bold ? " " : "")} style={{ color: sign && neg ? "var(--neg)" : sign && value > 0 ? "var(--pos)" : "inherit", fontWeight: bold ? 600 : "inherit" }}>{S.formatRupiah(value)}</span>;
}

Object.assign(window, {
  useStore, useLang, t, tStatus, Icon, Button, StatusBadge, Badge, Progress,
  Field, Input, Textarea, Select, MoneyInput, Segmented, DocLangToggle,
  Modal, useConfirm, Empty, PageHead, go, Money, S, I,
  imageFileToDataURL, ImagePicker
});
