// Shared UI primitives for the Goods In Portal — used by all three
// direction prototypes via window.GIUI.
// Kept deliberately minimal; direction-specific composition lives in
// each direction's own files.

function GIIcon({ name, size = 18, stroke = 1.75, color = "currentColor" }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!ref.current || !window.lucide) return;
    ref.current.innerHTML = "";
    const pascal = name.split("-").map(p => p.charAt(0).toUpperCase() + p.slice(1)).join("");
    const data = window.lucide.icons[pascal];
    if (!data) return;
    const svg = window.lucide.createElement(data);
    svg.setAttribute("width", size);
    svg.setAttribute("height", size);
    svg.setAttribute("stroke", color);
    svg.setAttribute("stroke-width", stroke);
    ref.current.appendChild(svg);
  }, [name, size, stroke, color]);
  return <span ref={ref} className="gi-icon" style={{ width: size, height: size, lineHeight: 0 }} />;
}

function GIBtn({ variant = "primary", size = "md", icon, iconAfter, children, onClick, disabled, type = "button", style }) {
  const cls = ["gi-btn", `gi-btn--${variant}`, size !== "md" ? `gi-btn--${size}` : ""].filter(Boolean).join(" ");
  return (
    <button type={type} className={cls} onClick={onClick} disabled={disabled} style={style}>
      {icon ? <GIIcon name={icon} size={16} /> : null}
      <span>{children}</span>
      {iconAfter ? <GIIcon name={iconAfter} size={16} /> : null}
    </button>
  );
}

function GIPill({ tone = "neutral", icon, children }) {
  return (
    <span className={`gi-pill gi-pill--${tone}`}>
      {icon ? <GIIcon name={icon} size={12} stroke={2} /> : null}
      {children}
    </span>
  );
}

function GIField({ label, hint, error, htmlFor, children, optional }) {
  return (
    <label className="gi-field" htmlFor={htmlFor}>
      {label ? (
        <span className="gi-field__label">
          {label}{optional ? <span style={{ marginLeft: 6, fontWeight: 500, textTransform: "none", letterSpacing: 0, color: "var(--fg-3)" }}>optional</span> : null}
        </span>
      ) : null}
      {children}
      {hint && !error ? <span className="gi-field__help">{hint}</span> : null}
      {error ? <span className="gi-field__error"><GIIcon name="alert-circle" size={13} /> {error}</span> : null}
    </label>
  );
}

function GIInput(props) { return <input className="gi-input" {...props} />; }
function GIMonoInput(props) { return <input className="gi-input gi-input--mono" {...props} />; }
function GITextarea(props) { return <textarea className="gi-textarea" {...props} />; }

function GICheck({ checked, onChange, label, sub }) {
  return (
    <label style={{ display: "flex", alignItems: "flex-start", gap: 10, cursor: "pointer" }}>
      <span
        className="gi-check"
        data-on={!!checked}
        onClick={(e) => { e.preventDefault(); onChange(!checked); }}
        role="checkbox" aria-checked={!!checked}
      >
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
      </span>
      {label ? (
        <span style={{ display: "flex", flexDirection: "column", gap: 2, lineHeight: 1.35, paddingTop: 1 }}>
          <span style={{ fontFamily: "var(--font-body)", fontSize: 14.5, color: "var(--fg-1)" }}>{label}</span>
          {sub ? <span style={{ fontSize: 12.5, color: "var(--fg-3)" }}>{sub}</span> : null}
        </span>
      ) : null}
    </label>
  );
}

function GIQty({ value, onChange, min = 0, max = 999999, step = 1 }) {
  return (
    <div className="gi-qty" onClick={(e) => e.stopPropagation()}>
      <button onClick={() => onChange(Math.max(min, value - step))} aria-label="Decrease">−</button>
      <input type="number" value={value} min={min} max={max} step={step}
        onChange={(e) => {
          const v = Number(e.target.value);
          if (Number.isNaN(v)) return;
          onChange(Math.max(min, Math.min(max, v)));
        }} />
      <button onClick={() => onChange(Math.min(max, value + step))} aria-label="Increase">+</button>
    </div>
  );
}

// Top portal bar — used by all three.
function GITopBar({ title = "Goods In Portal", subtitle = "Book a delivery slot", right }) {
  return (
    <header className="gi-topbar">
      <div className="gi-topbar__inner">
        <div className="gi-topbar__brand">
          <img src="/shared/assets/logo-type2-white.png" alt="JFH Horticultural Supplies" />
        </div>
        <div className="gi-topbar__title">
          <span className="gi-topbar__eyebrow">{subtitle}</span>
          <span className="gi-topbar__h">{title}</span>
        </div>
        <div className="gi-topbar__spacer" />
        {right || (
          <div className="gi-topbar__contact">
            <span><GIIcon name="phone" size={13} />&nbsp;&nbsp;Goods in · <strong>01270 212726</strong></span>
            <span><GIIcon name="mail" size={13} />&nbsp;&nbsp;<strong>goodsin@jfhhorticultural.com</strong></span>
          </div>
        )}
      </div>
    </header>
  );
}

// Shared booking-state hook. All directions go through this so we can guarantee
// identical data flow + reasonable defaults.
function useGIBooking() {
  const [state, setState] = React.useState({
    step: 0,                      // direction-specific
    poValidated: false,
    po: window.JFH_GI.PO,
    poNumber: "",
    supplierCode: "",
    deliveryType: null,           // id from DELIVERY_TYPES
    courier: "",
    courierOther: "",
    vehicleReg: "",
    driverName: "",
    driverPhone: "",
    palletCount: "",
    cartonCount: "",
    paperwork: null,              // { name, sizeKb }
    notes: "",
    // PO line selection — Map line.sku -> qty (0 = excluded)
    lineQty: Object.fromEntries(window.JFH_GI.PO.lines.map(l => [l.sku, window.JFH_GI.lineRemaining(l)])),
    fullDelivery: true,
    slotDay: 0,                   // 0..2
    slotDock: 1,                  // 1..3
    slotTime: null,               // "HH:MM"
    bookingRef: null,
  });
  const patch = React.useCallback((p) => setState(s => ({ ...s, ...(typeof p === "function" ? p(s) : p) })), []);
  return [state, patch];
}

/* ───────── Styled dialog (replaces window.confirm / window.prompt) ─────────
 * Usage:
 *   const ok = await GIDialog.confirm({ title: "Cancel booking?", message: "...", confirmLabel: "Cancel", danger: true });
 *   const reason = await GIDialog.prompt({ title: "Reason", placeholder: "Optional" });
 *
 * Returns: confirm → boolean. prompt → string|null (null = cancelled).
 * Modal is rendered into a transient root attached to document.body — no
 * React-tree integration required, so it can be called from any handler.
 */

function GIDialogView({ kind, title, message, confirmLabel = "OK", cancelLabel = "Cancel", danger, defaultValue = "", placeholder = "", multiline, onResolve }) {
  const [value, setValue] = React.useState(defaultValue);
  const inputRef = React.useRef(null);

  // One-time focus on mount. Re-running this on every value change was
  // selecting the input contents and replacing them on the next keystroke
  // (the "only one character lands" bug).
  React.useEffect(() => {
    if (inputRef.current) {
      try { inputRef.current.focus(); inputRef.current.select?.(); } catch {}
    }
  }, []);

  // Keyboard shortcuts — re-bound when `value` changes so Enter resolves
  // with the current value, but listener is removed cleanly each time.
  React.useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape") { e.preventDefault(); onResolve(kind === "confirm" ? false : null); }
      if (e.key === "Enter" && !multiline && (e.metaKey || e.ctrlKey || !e.target.matches("textarea"))) {
        e.preventDefault();
        onResolve(kind === "confirm" ? true : value);
      }
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [kind, value, multiline, onResolve]);

  return (
    <div
      onClick={() => onResolve(kind === "confirm" ? false : null)}
      style={{
        position: "fixed", inset: 0, background: "rgba(15,27,20,0.55)", zIndex: 10000,
        display: "flex", alignItems: "center", justifyContent: "center",
        fontFamily: "var(--font-body)", padding: 16,
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background: "white", borderRadius: 14, boxShadow: "0 24px 48px rgba(15,27,20,0.24)",
          width: "100%", maxWidth: 480, padding: 24, color: "var(--fg-1)",
        }}
      >
        {title ? (
          <h3 style={{ margin: 0, fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 20, color: "var(--jfh-mountain-green)" }}>
            {title}
          </h3>
        ) : null}
        {message ? (
          <p style={{ margin: title ? "10px 0 16px" : "0 0 16px", color: "var(--fg-2)", fontSize: 14.5, lineHeight: 1.5 }}>
            {message}
          </p>
        ) : null}
        {kind === "prompt" ? (
          multiline ? (
            <textarea
              ref={inputRef}
              value={value}
              onChange={(e) => setValue(e.target.value)}
              placeholder={placeholder}
              className="gi-textarea"
              style={{ width: "100%" }}
            />
          ) : (
            <input
              ref={inputRef}
              value={value}
              onChange={(e) => setValue(e.target.value)}
              placeholder={placeholder}
              className="gi-input"
              style={{ width: "100%" }}
            />
          )
        ) : null}
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 18 }}>
          <button
            onClick={() => onResolve(kind === "confirm" ? false : null)}
            className="gi-btn gi-btn--ghost"
          >
            {cancelLabel}
          </button>
          <button
            onClick={() => onResolve(kind === "confirm" ? true : value)}
            className={`gi-btn ${danger ? "gi-btn--primary" : "gi-btn--primary"}`}
            style={danger ? { background: "var(--status-danger)", borderColor: "var(--status-danger)" } : undefined}
          >
            {confirmLabel}
          </button>
        </div>
      </div>
    </div>
  );
}

function _giDialogShow(opts) {
  return new Promise((resolve) => {
    const container = document.createElement("div");
    document.body.appendChild(container);
    const root = ReactDOM.createRoot(container);
    function finish(v) {
      root.unmount();
      container.remove();
      resolve(v);
    }
    root.render(<GIDialogView {...opts} onResolve={finish} />);
    // Re-render lucide icons inside the modal (in case the consumer relied on that).
    setTimeout(() => { try { window.lucide?.createIcons?.(); } catch {} }, 0);
  });
}

const GIDialog = {
  confirm: (opts) => _giDialogShow({ kind: "confirm", ...opts }),
  prompt: (opts) => _giDialogShow({ kind: "prompt", confirmLabel: "Save", ...opts }),
};

Object.assign(window, { GIIcon, GIBtn, GIPill, GIField, GIInput, GIMonoInput, GITextarea, GICheck, GIQty, GITopBar, useGIBooking, GIDialog });
