/* NGIPL PLM — shared UI primitives (icons, buttons, dialogs, inputs) */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------- Icons (Lucide-style line art, stroke 1.75) ---------- */
function mkIcon(children) {
  return function Icon({ size = 16, style }) {
    return (
      <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
        strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" style={style} aria-hidden="true">
        {children}
      </svg>
    );
  };
}
const ISearch = mkIcon(<React.Fragment><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></React.Fragment>);
const IPlus = mkIcon(<React.Fragment><path d="M5 12h14"></path><path d="M12 5v14"></path></React.Fragment>);
const IX = mkIcon(<React.Fragment><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></React.Fragment>);
const IPencil = mkIcon(<React.Fragment><path d="M12 20h9"></path><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path></React.Fragment>);
const IPrinter = mkIcon(<React.Fragment><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></React.Fragment>);
const IHistory = mkIcon(<React.Fragment><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M12 7v5l4 2"></path></React.Fragment>);
const IAlert = mkIcon(<React.Fragment><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></React.Fragment>);
const ICheck = mkIcon(<polyline points="20 6 9 17 4 12"></polyline>);
const ITrash = mkIcon(<React.Fragment><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></React.Fragment>);
const IChevronR = mkIcon(<polyline points="9 18 15 12 9 6"></polyline>);
const ISliders = mkIcon(<React.Fragment><line x1="4" y1="21" x2="4" y2="14"></line><line x1="4" y1="10" x2="4" y2="3"></line><line x1="12" y1="21" x2="12" y2="12"></line><line x1="12" y1="8" x2="12" y2="3"></line><line x1="20" y1="21" x2="20" y2="16"></line><line x1="20" y1="12" x2="20" y2="3"></line><line x1="1" y1="14" x2="7" y2="14"></line><line x1="9" y1="8" x2="15" y2="8"></line><line x1="17" y1="16" x2="23" y2="16"></line></React.Fragment>);
const IArrowR = mkIcon(<React.Fragment><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></React.Fragment>);
const IJump = mkIcon(<React.Fragment><polyline points="15 14 20 9 15 4"></polyline><path d="M4 20v-7a4 4 0 0 1 4-4h12"></path></React.Fragment>);
const IPercent = mkIcon(<React.Fragment><line x1="19" y1="5" x2="5" y2="19"></line><circle cx="6.5" cy="6.5" r="2.5"></circle><circle cx="17.5" cy="17.5" r="2.5"></circle></React.Fragment>);
const IChevronL = mkIcon(<polyline points="15 18 9 12 15 6"></polyline>);
const ICalendar = mkIcon(<React.Fragment><rect x="3" y="4" width="18" height="18" rx="0"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></React.Fragment>);
const IDownload = mkIcon(<React.Fragment><path d="M12 3v12"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="4" y1="21" x2="20" y2="21"></line></React.Fragment>);

/* ---------- Category icons — crisp line-art redraws of the diary-cover motifs ---------- */
const CATEGORY_ICON_PATHS = {
  /* sachet with crimped seals (sugar single serve) */
  "cat-ss": (
    <React.Fragment>
      <rect x="6.5" y="3.5" width="11" height="17"></rect>
      <path d="M6.5 6.5h11"></path>
      <path d="M6.5 17.5h11"></path>
      <path d="M10 12h4"></path>
    </React.Fragment>
  ),
  /* serving cloche on tray (F&B) */
  "cat-fnb": (
    <React.Fragment>
      <path d="M4.5 16.5a7.5 7.5 0 0 1 15 0"></path>
      <path d="M3 16.5h18"></path>
      <path d="M12 9v-1.2"></path>
      <circle cx="12" cy="6.6" r="1.2"></circle>
    </React.Fragment>
  ),
  /* pump bottle (cosmetics / wet amenities) */
  "cat-cos": (
    <React.Fragment>
      <rect x="8.5" y="9.5" width="7" height="11"></rect>
      <path d="M10.5 9.5v-3h3v3"></path>
      <path d="M12 6.5V4H8.2v2.2"></path>
    </React.Fragment>
  ),
  /* safety razor (guest amenities kit) */
  "cat-ga": (
    <React.Fragment>
      <rect x="7.5" y="3.5" width="9" height="4.5"></rect>
      <path d="M10.5 5.75h3"></path>
      <path d="M12 8v11.5"></path>
      <path d="M10.5 19.5h3"></path>
    </React.Fragment>
  ),
  /* broom (housekeeping) */
  "cat-hk": (
    <React.Fragment>
      <path d="M12 2.5V11"></path>
      <path d="M8.5 11h7l1.8 8.5H6.7z"></path>
      <path d="M10.3 14.5l-.5 5"></path>
      <path d="M13.7 14.5l.5 5"></path>
    </React.Fragment>
  ),
  /* carton (other) */
  "cat-other": (
    <React.Fragment>
      <rect x="4.5" y="7.5" width="15" height="12"></rect>
      <path d="M4.5 7.5 7 4h10l2.5 3.5"></path>
      <path d="M12 4v3.5"></path>
    </React.Fragment>
  ),
};
function CatIcon({ catId, size = 18 }) {
  const paths = CATEGORY_ICON_PATHS[catId] || CATEGORY_ICON_PATHS["cat-other"];
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
      strokeWidth="1.9" strokeLinecap="square" strokeLinejoin="miter" aria-hidden="true" style={{ flex: "none" }}>
      {paths}
    </svg>
  );
}

/* ---------- Button (mirrors NGIPL DS Button) ---------- */
const PLM_BTN_CSS = `
.ngipl-btn{font-family:var(--font-body);font-weight:var(--fw-semibold);text-transform:uppercase;letter-spacing:var(--track-caps);border-radius:var(--radius-0);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:8px;border:var(--bw-hairline) solid transparent;transition:background-color var(--dur-fast) var(--ease-brand),color var(--dur-fast) var(--ease-brand),border-color var(--dur-fast) var(--ease-brand);white-space:nowrap;}
.ngipl-btn:focus-visible{outline:var(--focus-ring-width) solid var(--focus-ring);outline-offset:var(--focus-ring-offset);}
.ngipl-btn--sm{height:32px;padding:0 14px;font-size:11px;}
.ngipl-btn--md{height:40px;padding:0 20px;font-size:12px;}
.ngipl-btn--primary{background:var(--action-primary);color:var(--text-inverse);}
.ngipl-btn--primary:hover{background:var(--action-primary-hover);}
.ngipl-btn--primary:active{background:var(--action-primary-active);}
.ngipl-btn--secondary{background:var(--surface-card);color:var(--text-display);border-color:var(--border-strong);}
.ngipl-btn--secondary:hover{background:var(--surface-sunken);}
.ngipl-btn--ghost{background:transparent;color:var(--text-display);}
.ngipl-btn--ghost:hover{background:var(--surface-sunken);}
.ngipl-btn--danger{background:var(--red-700);color:var(--text-inverse);}
.ngipl-btn--danger:hover{background:#8f2a2a;}
.ngipl-btn[disabled]{background:var(--gray-100);color:var(--gray-400);border-color:transparent;cursor:not-allowed;}
.ngipl-iconbtn{appearance:none;background:none;border:var(--bw-hairline) solid transparent;cursor:pointer;width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;color:var(--gray-700);transition:all var(--dur-fast) var(--ease-brand);border-radius:var(--radius-0);}
.ngipl-iconbtn:hover{background:var(--surface-sunken);color:var(--ngipl-black);}
`;
function injectCss(id, css) {
  if (document.getElementById(id)) return;
  const el = document.createElement("style");
  el.id = id;
  el.textContent = css;
  document.head.appendChild(el);
}
function Btn({ variant = "primary", size = "md", children, ...rest }) {
  injectCss("plm-btn-css", PLM_BTN_CSS);
  return (
    <button type="button" className={"ngipl-btn ngipl-btn--" + size + " ngipl-btn--" + variant} {...rest}>{children}</button>
  );
}
function IconBtn({ title, children, ...rest }) {
  injectCss("plm-btn-css", PLM_BTN_CSS);
  return <button type="button" className="ngipl-iconbtn" title={title} aria-label={title} {...rest}>{children}</button>;
}

/* ---------- Dialog ---------- */
function Dialog({ title, onClose, width, footer, children }) {
  useEffect(() => {
    function onKey(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);
  return (
    <div className="dlg-scrim" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="dlg" style={width ? { width: width } : null} role="dialog" aria-modal="true">
        <div className="dlg-head">
          <div className="dlg-title">{title}</div>
          <IconBtn title="Close" onClick={onClose}><IX size={16}></IX></IconBtn>
        </div>
        <div className="dlg-body">{children}</div>
        {footer ? <div className="dlg-foot">{footer}</div> : null}
      </div>
    </div>
  );
}

/* ---------- Form field helpers ---------- */
function Field({ label, children, style }) {
  return (
    <div style={style}>
      <label className="f-label">{label}</label>
      {children}
    </div>
  );
}
function Seg({ options, value, onChange }) {
  return (
    <div className="seg">
      {options.map((o) => (
        <button key={o.value} type="button" className={o.value === value ? "on" : ""} onClick={() => onChange(o.value)}>{o.label}</button>
      ))}
    </div>
  );
}

/* ---------- Inline-editable rate cell ---------- */
function RateCell({ value, onCommit, prefix }) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState("");
  const ref = useRef(null);
  useEffect(() => { if (editing && ref.current) { ref.current.focus(); ref.current.select(); } }, [editing]);
  function start() { setDraft(String(value)); setEditing(true); }
  function commit() {
    setEditing(false);
    const n = parseFloat(draft);
    if (isNaN(n) || n < 0) return;
    if (Math.abs(n - value) < 0.0001) return;
    onCommit(Math.round(n * 100) / 100);
  }
  if (editing) {
    return (
      <input className="rate-input" ref={ref} value={draft}
        onChange={(e) => setDraft(e.target.value)}
        onBlur={commit}
        onKeyDown={(e) => { if (e.key === "Enter") commit(); if (e.key === "Escape") setEditing(false); }} />
    );
  }
  return (
    <span className="rate-view tnum" title="Click to edit rate" onClick={start}>
      {prefix}{PLM.fmtRate(value)}
    </span>
  );
}

/* ---------- Toast ---------- */
function ToastHost({ toasts }) {
  return (
    <div className="toast-wrap">
      {toasts.map((t) => <div className="toast" key={t.id}>{t.msg}</div>)}
    </div>
  );
}

/* ---------- W.E.F. date picker ---------- */
const WEF_MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
function parseWefDate(str) {
  if (!str) return null;
  const m = /^(\d{1,2})\s+([A-Za-z]+)\.?,?\s+(\d{4})$/.exec(String(str).trim());
  if (m) {
    const mi = WEF_MONTHS.findIndex((x) => x.toLowerCase().slice(0, 3) === m[2].toLowerCase().slice(0, 3));
    if (mi >= 0) return new Date(+m[3], mi, +m[1]);
  }
  const d = new Date(str);
  return isNaN(d.getTime()) ? null : d;
}
function fmtWefDate(d) { return d.getDate() + " " + WEF_MONTHS[d.getMonth()] + " " + d.getFullYear(); }
function sameDay(a, b) { return a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }

function useOutsideClose(ref, onClose) {
  useEffect(() => {
    function onDown(e) { if (ref.current && !ref.current.contains(e.target)) onClose(); }
    function onKey(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("mousedown", onDown);
    document.addEventListener("keydown", onKey);
    return () => { document.removeEventListener("mousedown", onDown); document.removeEventListener("keydown", onKey); };
  }, [ref, onClose]);
}

/* Calendar panel. Always opens on TODAY's month so updating W.E.F. to the current date is one click. */
function WefCalendar({ value, onPick, align }) {
  const selected = parseWefDate(value);
  const today = new Date();
  const [view, setView] = useState(() => new Date(today.getFullYear(), today.getMonth(), 1));
  const offset = (view.getDay() + 6) % 7; /* Monday-start */
  const dim = new Date(view.getFullYear(), view.getMonth() + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < offset; i++) cells.push(null);
  for (let d = 1; d <= dim; d++) cells.push(new Date(view.getFullYear(), view.getMonth(), d));
  return (
    <div className={"cal-pop" + (align === "right" ? " cal-pop--right" : "")} onMouseDown={(e) => e.stopPropagation()}>
      <div className="cal-head">
        <IconBtn title="Previous month" onClick={() => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1))}><IChevronL size={14}></IChevronL></IconBtn>
        <span className="cal-title tnum">{WEF_MONTHS[view.getMonth()]} {view.getFullYear()}</span>
        <IconBtn title="Next month" onClick={() => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1))}><IChevronR size={14}></IChevronR></IconBtn>
      </div>
      <div className="cal-grid">
        {["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"].map((d) => <span key={d} className="cal-dow">{d}</span>)}
        {cells.map((d, i) => d ? (
          <button key={i} type="button"
            className={"cal-day tnum" + (sameDay(d, today) ? " cal-day--today" : "") + (sameDay(d, selected) ? " cal-day--sel" : "")}
            title={sameDay(d, today) ? "Today" : undefined}
            onClick={() => onPick(d)}>{d.getDate()}</button>
        ) : <span key={i}></span>)}
      </div>
      <div className="cal-foot">
        <span className="caption">Today</span>
        <button type="button" className="cal-today" onClick={() => onPick(today)}>{fmtWefDate(today)}</button>
      </div>
    </div>
  );
}

/* Input-look trigger + calendar, for settings / print forms */
function WefField({ value, onChange, btnStyle, align }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useOutsideClose(ref, () => setOpen(false));
  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button type="button" className="f-input wef-field" style={btnStyle} onClick={() => setOpen((o) => !o)}>
        <ICalendar size={14} style={{ color: "var(--gray-600)", flex: "none" }}></ICalendar>
        <span>{value}</span>
      </button>
      {open ? <WefCalendar value={value} align={align} onPick={(d) => { onChange(fmtWefDate(d)); setOpen(false); }}></WefCalendar> : null}
    </div>
  );
}

Object.assign(window, {
  ISearch, IPlus, IX, IPencil, IPrinter, IHistory, IAlert, ICheck, ITrash, IChevronR, IChevronL, ICalendar, IDownload, ISliders, IArrowR, IJump, IPercent,
  CatIcon,
  Btn, IconBtn, Dialog, Field, Seg, RateCell, ToastHost, injectCss,
  WefCalendar, WefField, parseWefDate, fmtWefDate, useOutsideClose,
});
