// components.jsx — shared UI primitives
const { useState, useRef, useEffect } = React;

/* ---------------- Button ---------------- */
function Button({ children, variant = "primary", size = "md", icon, iconRight, full, onClick, disabled, type = "button", style = {} }) {
  const [hover, setHover] = useState(false);
  const [press, setPress] = useState(false);
  const pads = { sm: "8px 14px", md: "11px 20px", lg: "14px 26px" };
  const fs = { sm: 13, md: 14.5, lg: 16 };
  const base = {
    display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 9,
    fontFamily: "var(--font-sans)", fontWeight: 500, fontSize: fs[size], lineHeight: 1,
    padding: pads[size], borderRadius: "var(--r-pill)", border: "1px solid transparent",
    width: full ? "100%" : undefined, transition: "all 140ms ease", whiteSpace: "nowrap",
    opacity: disabled ? 0.5 : 1, pointerEvents: disabled ? "none" : "auto",
    transform: press ? "translateY(1px)" : "none",
  };
  const variants = {
    primary: { background: hover ? "var(--accent-600)" : "var(--accent)", color: "#fff", boxShadow: hover ? "var(--shadow-cta)" : "none" },
    dark: { background: hover ? "var(--brand-700)" : "var(--brand)", color: "#fff" },
    secondary: { background: hover ? "var(--bg-mist)" : "var(--surface)", color: "var(--fg-strong)", borderColor: "var(--border-strong)" },
    ghost: { background: hover ? "var(--bg-mist)" : "transparent", color: "var(--fg-body)" },
    link: { background: "transparent", color: "var(--accent-700)", padding: "4px 2px" },
  };
  return (
    <button type={type} onClick={onClick} disabled={disabled}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => { setHover(false); setPress(false); }}
      onMouseDown={() => setPress(true)} onMouseUp={() => setPress(false)}
      style={{ ...base, ...variants[variant], ...style }}>
      {icon && <Icon name={icon} size={size === "lg" ? 19 : 17} stroke={2.1} />}
      {children}
      {iconRight && <Icon name={iconRight} size={size === "lg" ? 19 : 17} stroke={2.1} />}
    </button>
  );
}

/* ---------------- Card ---------------- */
function Card({ children, pad = 24, style = {}, hover = false, onClick, className = "" }) {
  const [h, setH] = useState(false);
  return (
    <div className={className} onClick={onClick}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--r-2xl)",
        padding: pad, boxShadow: hover && h ? "var(--shadow-md)" : "var(--shadow-card)",
        transition: "box-shadow 200ms ease, transform 200ms ease",
        transform: hover && h ? "translateY(-2px)" : "none",
        cursor: onClick ? "pointer" : "default", ...style,
      }}>
      {children}
    </div>
  );
}

/* ---------------- Eyebrow ---------------- */
function Eyebrow({ children, color }) {
  return <div className="eyebrow" style={color ? { color } : undefined}>{children}</div>;
}

/* ---------------- StatusDot ---------------- */
function StatusDot({ color = "var(--success)", pulse = false, size = 8 }) {
  return <span style={{ width: size, height: size, borderRadius: "50%", background: color, display: "inline-block", flex: "none", animation: pulse ? "pulseDot 1.8s infinite" : "none" }} />;
}

/* ---------------- Badge / Pill ---------------- */
function Badge({ children, tone = "neutral", style = {} }) {
  const tones = {
    neutral: { bg: "var(--bg-mist)", fg: "var(--fg-mute)" },
    accent: { bg: "var(--accent-soft)", fg: "var(--accent-700)" },
    brand: { bg: "var(--brand-soft)", fg: "var(--brand)" },
    success: { bg: "var(--success-soft)", fg: "#108a52" },
    warn: { bg: "var(--warn-soft)", fg: "#a36a00" },
    danger: { bg: "var(--danger-soft)", fg: "var(--danger)" },
  };
  const t = tones[tone] || tones.neutral;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6, background: t.bg, color: t.fg,
      fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 10.5, letterSpacing: "0.6px",
      textTransform: "uppercase", padding: "5px 10px", borderRadius: "var(--r-pill)", ...style,
    }}>{children}</span>
  );
}

/* ---------------- Field (label wrapper) ---------------- */
function Field({ label, hint, children, style = {} }) {
  return (
    <label style={{ display: "block", ...style }}>
      {label && <div style={{ fontSize: 13, fontWeight: 500, color: "var(--fg-strong)", marginBottom: 7 }}>{label}</div>}
      {children}
      {hint && <div style={{ fontSize: 12, color: "var(--fg-mute)", marginTop: 6 }}>{hint}</div>}
    </label>
  );
}

const inputStyle = {
  width: "100%", padding: "11px 13px", fontSize: 14.5, color: "var(--fg-strong)",
  background: "var(--surface)", border: "1px solid var(--border-strong)", borderRadius: "var(--r-sm)",
  outline: "none", transition: "border-color 140ms ease, box-shadow 140ms ease",
};
function TextInput({ value, onChange, placeholder, type = "text", mono, style = {}, ...rest }) {
  const [f, setF] = useState(false);
  // Guard: @babel/standalone compiles each <script type="text/babel"> in shared global scope,
  // so a later file's top-level `_excluded` helper can clobber this destructure's exclude list
  // and leak `mono` onto the <input> (React warns). Strip it explicitly. (Multi-script dev launchers.)
  if (rest && "mono" in rest) delete rest.mono;
  return (
    <input type={type} value={value} placeholder={placeholder}
      onChange={e => onChange && onChange(e.target.value)}
      onFocus={() => setF(true)} onBlur={() => setF(false)}
      style={{ ...inputStyle, fontFamily: mono ? "var(--font-mono)" : "var(--font-sans)",
        borderColor: f ? "var(--brand)" : "var(--border-strong)",
        boxShadow: f ? "0 0 0 3px var(--brand-soft)" : "none", ...style }} {...rest} />
  );
}
function Select({ value, onChange, options, placeholder, style = {} }) {
  const [f, setF] = useState(false);
  return (
    <div style={{ position: "relative" }}>
      <select value={value} onChange={e => onChange && onChange(e.target.value)}
        onFocus={() => setF(true)} onBlur={() => setF(false)}
        style={{ ...inputStyle, appearance: "none", paddingRight: 38, cursor: "pointer",
          color: value ? "var(--fg-strong)" : "var(--fg-faint)",
          borderColor: f ? "var(--brand)" : "var(--border-strong)",
          boxShadow: f ? "0 0 0 3px var(--brand-soft)" : "none", ...style }}>
        {placeholder && <option value="">{placeholder}</option>}
        {options.map(o => typeof o === "string"
          ? <option key={o} value={o}>{o}</option>
          : <option key={o.value} value={o.value}>{o.label}</option>)}
      </select>
      <span style={{ position: "absolute", right: 12, top: "50%", transform: "translateY(-50%)", pointerEvents: "none", color: "var(--fg-mute)" }}>
        <Icon name="chevron-down" size={16} />
      </span>
    </div>
  );
}

/* ---------------- Vehicle glyph (icon in soft badge) ---------------- */
function VehicleGlyph({ icon, active = false, size = 48 }) {
  return (
    <span style={{
      width: size, height: size, borderRadius: 14, flex: "none",
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      background: active ? "var(--accent)" : "var(--brand-soft)",
      color: active ? "#fff" : "var(--brand)", transition: "all 160ms ease",
    }}>
      <Icon name={icon} size={size * 0.5} stroke={1.9} />
    </span>
  );
}

/* ---------------- Capacity meter ---------------- */
function CapacityMeter({ pct, active }) {
  return (
    <div style={{ height: 5, background: "var(--bg-mist-2)", borderRadius: 999, overflow: "hidden" }}>
      <div style={{ height: "100%", width: (pct * 100) + "%", background: active ? "var(--accent)" : "var(--brand)", borderRadius: 999, transition: "width 300ms ease" }} />
    </div>
  );
}

/* ---------------- Barcode (decorative Code128-style) ---------------- */
function Barcode({ value = "", height = 56, width = 280 }) {
  // deterministic bar widths from the string
  let seed = 0; for (let i = 0; i < value.length; i++) seed = (seed * 31 + value.charCodeAt(i)) >>> 0;
  const rng = () => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; };
  const bars = []; let x = 0;
  while (x < width) {
    const w = 1 + Math.floor(rng() * 4);
    const dark = rng() > 0.45;
    if (dark) bars.push(<rect key={x} x={x} y="0" width={w} height={height} fill="#16121f" />);
    x += w;
  }
  return <svg width="100%" height={height} viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" style={{ display: "block" }}>{bars}</svg>;
}

/* ---------------- QR (decorative) ---------------- */
function QRCode({ value = "", size = 96 }) {
  const n = 21;
  let seed = 7; for (let i = 0; i < value.length; i++) seed = (seed * 33 + value.charCodeAt(i)) >>> 0;
  const rng = () => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; };
  const cell = size / n;
  const rects = [];
  const finder = (ox, oy) => {
    for (let i = 0; i < 7; i++) for (let j = 0; j < 7; j++) {
      const edge = i === 0 || i === 6 || j === 0 || j === 6;
      const core = i >= 2 && i <= 4 && j >= 2 && j <= 4;
      if (edge || core) rects.push(<rect key={`f${ox}${oy}${i}${j}`} x={(ox + i) * cell} y={(oy + j) * cell} width={cell} height={cell} fill="#16121f" />);
    }
  };
  for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) {
    const inFinder = (i < 8 && j < 8) || (i > n - 9 && j < 8) || (i < 8 && j > n - 9);
    if (inFinder) continue;
    if (rng() > 0.55) rects.push(<rect key={`${i}-${j}`} x={i * cell} y={j * cell} width={cell} height={cell} fill="#16121f" />);
  }
  finder(0, 0); finder(n - 7, 0); finder(0, n - 7);
  return <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: "block" }}>{rects}</svg>;
}

/* ---------------- Items editor (shared: quote + booking) — roomy, labelled, prefilled ---------------- */
function ItemsEditor({ items, setItems }) {
  const setItem = (i, k, v) => setItems(prev => prev.map((it, idx) => idx === i ? { ...it, [k]: v } : it));
  const add = () => setItems(prev => [...prev, window.FX.blankItem()]);
  const rm = (i) => setItems(prev => prev.length > 1 ? prev.filter((_, idx) => idx !== i) : prev);
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      {items.map((it, i) => (
        <div key={i} style={{ border: "1px solid var(--border)", borderRadius: "var(--r-md)", padding: 15, background: "var(--surface)" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
            <span style={{ fontSize: 12.5, fontWeight: 700, color: "var(--fg-strong)" }}>Item {i + 1}</span>
            {items.length > 1 && <button onClick={() => rm(i)} title="Remove item" style={{ background: "var(--bg-mist)", border: "none", borderRadius: 7, width: 30, height: 30, display: "inline-flex", alignItems: "center", justifyContent: "center", color: "var(--fg-mute)", cursor: "pointer" }}><Icon name="x" size={15} /></button>}
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "96px 1fr", gap: 12, marginBottom: 12 }}>
            <Field label="Quantity"><TextInput type="number" value={it.qty} onChange={v => setItem(i, "qty", v)} mono /></Field>
            <Field label="Item type"><Select value={it.type} onChange={v => setItem(i, "type", v)} options={window.FX.ITEM_TYPES} /></Field>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10 }}>
            <Field label="Length (cm)"><TextInput type="number" value={it.l} onChange={v => setItem(i, "l", v)} mono /></Field>
            <Field label="Width (cm)"><TextInput type="number" value={it.w} onChange={v => setItem(i, "w", v)} mono /></Field>
            <Field label="Height (cm)"><TextInput type="number" value={it.h} onChange={v => setItem(i, "h", v)} mono /></Field>
            <Field label="Weight (kg)"><TextInput type="number" value={it.weight} onChange={v => setItem(i, "weight", v)} mono /></Field>
          </div>
        </div>
      ))}
      <button onClick={add} style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8, padding: "12px 14px", background: "var(--surface)", border: "1px dashed var(--border-strong)", borderRadius: "var(--r-md)", color: "var(--brand)", fontSize: 13.5, fontWeight: 600, cursor: "pointer" }}>
        <Icon name="plus" size={16} /> Add another item
      </button>
    </div>
  );
}
Object.assign(window, { ItemsEditor });

/* ---------------- Page header ---------------- */
function PageHeader({ eyebrow, title, sub, actions }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", gap: 24, flexWrap: "wrap", marginBottom: 28 }}>
      <div>
        {eyebrow && <Eyebrow>{eyebrow}</Eyebrow>}
        <h1 style={{ margin: eyebrow ? "10px 0 0" : 0, fontSize: 30, fontWeight: 700, letterSpacing: "-0.8px", color: "var(--fg-strong)" }}>{title}</h1>
        {sub && <p style={{ margin: "8px 0 0", fontSize: 15, color: "var(--fg-mute)", maxWidth: 620, lineHeight: 1.5 }}>{sub}</p>}
      </div>
      {actions && <div style={{ display: "flex", gap: 10 }}>{actions}</div>}
    </div>
  );
}

/* ---------------- Empty / spinner ---------------- */
function Spinner({ size = 18, color = "#fff" }) {
  return <span style={{ width: size, height: size, border: `2px solid ${color}`, borderTopColor: "transparent", borderRadius: "50%", display: "inline-block", animation: "spin 0.7s linear infinite" }} />;
}

Object.assign(window, {
  Button, Card, Eyebrow, StatusDot, Badge, Field, TextInput, Select,
  VehicleGlyph, CapacityMeter, Barcode, QRCode, PageHeader, Spinner, inputStyle,
});
