/* ============================================================
   INside Cotizador Pro — Shared UI kit + helpers
   Exports everything onto window for the other babel scripts.
   ============================================================ */

// ---------- formatting helpers ----------
const fmtMoney = (n) =>
  "$" + (Number(n) || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const fmtNum = (n, d = 2) =>
  (Number(n) || 0).toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: d });
const fmtPct = (n) => (Number(n) || 0).toFixed(1) + "%";

// ---------- margin logic ----------
// semáforo: <15 rojo, 15–25 amarillo, >25 verde
function marginTier(pct) {
  if (pct < 15) return { key: "low", color: "var(--red)", label: "Bajo" };
  if (pct < 25) return { key: "mid", color: "var(--amber)", label: "Aceptable" };
  return { key: "ok", color: "var(--green)", label: "Óptimo" };
}

// resolve item image per "lógica C": custom override else product image
function resolveItemImage(item, product) {
  if (item && item.item_image_url) {
    return { url: item.item_image_url, label: item.image_label || null, source: "custom" };
  }
  return { url: (product && product.image_url) || null, label: null, source: "product" };
}

// effective unit price from margin hierarchy (for catalog display only)
function effectiveMargin(product, settings) {
  if (product.margin_pct != null) return product.margin_pct;
  const cat = settings.category_margin[product.category];
  if (cat != null) return cat;
  return settings.global_margin;
}

// ---------- minimal line icon set ----------
const ICON_PATHS = {
  catalog: "M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z",
  quote: "M4 3h11l5 5v13H4zM15 3v5h5",
  history: "M3 12a9 9 0 1 0 9-9 9 9 0 0 0-7.5 4M3 4v4h4M12 7v5l3 3",
  settings: "M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM19 12a7 7 0 0 0-.1-1l2-1.6-2-3.4-2.4 1a7 7 0 0 0-1.7-1L14.5 2h-5l-.3 2.4a7 7 0 0 0-1.7 1l-2.4-1-2 3.4L3 11a7 7 0 0 0 0 2l-2 1.6 2 3.4 2.4-1a7 7 0 0 0 1.7 1l.3 2.4h5l.3-2.4a7 7 0 0 0 1.7-1l2.4 1 2-3.4-2-1.6a7 7 0 0 0 .1-1z",
  search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16zM21 21l-4.3-4.3",
  plus: "M12 5v14M5 12h14",
  check: "M20 6 9 17l-5-5",
  x: "M18 6 6 18M6 6l12 12",
  edit: "M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z",
  reset: "M3 12a9 9 0 1 0 3-6.7L3 8M3 3v5h5",
  upload: "M12 16V4M7 9l5-5 5 5M5 20h14",
  download: "M12 4v12M7 11l5 5 5-5M5 20h14",
  trash: "M3 6h18M8 6V4h8v2M6 6l1 14h10l1-14",
  chevron: "M9 6l6 6-6 6",
  eye: "M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12zM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
  eyeoff: "M3 3l18 18M10.6 10.6a3 3 0 0 0 4 4M9.4 5.2A10 10 0 0 1 12 5c6 0 10 7 10 7a17 17 0 0 1-3.4 4M6.6 6.6A17 17 0 0 0 2 12s4 7 10 7a10 10 0 0 0 2.6-.3",
  copy: "M9 9h11v11H9zM5 15H4V4h11v1",
  drag: "M9 5h.01M9 12h.01M9 19h.01M15 5h.01M15 12h.01M15 19h.01",
  doc: "M6 2h9l5 5v15H6zM15 2v5h5M9 13h6M9 17h6",
  brand: "M3 21V8l9-5 9 5v13M3 21h18M9 21v-6h6v6",
  logout: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9",
  user: "M20 21a8 8 0 1 0-16 0M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z",
  lock: "M5 11h14v10H5zM8 11V7a4 4 0 0 1 8 0v4",
};

function Icon({ name, size = 18, stroke = 2, className = "", style }) {
  const d = ICON_PATHS[name] || "";
  return (
    <svg className={className} width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" style={style}>
      {d.split("M").filter(Boolean).map((seg, i) => <path key={i} d={"M" + seg} />)}
    </svg>
  );
}

// ---------- category badge (monochrome — differentiated by label) ----------
function CatBadge({ cat, size = "sm" }) {
  const meta = window.AppData.CATEGORIES[cat] || { label: cat };
  const pad = size === "sm" ? "3px 8px" : "5px 11px";
  const fs = size === "sm" ? 10 : 11;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6, padding: pad, fontSize: fs,
      fontWeight: 600, letterSpacing: ".08em", textTransform: "uppercase", borderRadius: 6,
      fontFamily: "var(--mono)",
      color: "color-mix(in srgb, var(--text) 80%, transparent)",
      background: "color-mix(in srgb, var(--text) 6%, transparent)",
      border: "1px solid color-mix(in srgb, var(--text) 16%, transparent)",
    }}>
      <span style={{ width: 5, height: 5, borderRadius: 9, background: "color-mix(in srgb, var(--text) 55%, transparent)" }} />
      {meta.label}
    </span>
  );
}

// ---------- margin pill (semáforo) ----------
function MarginPill({ pct, showLabel = false }) {
  const t = marginTier(pct);
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6, padding: "3px 9px", borderRadius: 20,
      fontFamily: "var(--mono)", fontSize: 12, fontWeight: 600, color: t.color,
      background: t.color.replace("var(--", "").length ? "color-mix(in oklch, " + t.color + " 14%, transparent)" : "transparent",
      border: "1px solid color-mix(in oklch, " + t.color + " 30%, transparent)",
      whiteSpace: "nowrap",
    }}>
      <span style={{ width: 6, height: 6, borderRadius: 8, background: t.color }} />
      {fmtPct(pct)}{showLabel ? " · " + t.label : ""}
    </span>
  );
}

// ---------- status badge ----------
const STATUS_META = {
  draft:    { label: "Borrador",  color: "var(--muted)" },
  sent:     { label: "Enviada",   color: "oklch(0.52 0.13 245)" },
  accepted: { label: "Ganada",    color: "var(--green)" },
  rejected: { label: "Perdida",   color: "var(--red)" },
};
function StatusBadge({ status }) {
  const m = STATUS_META[status] || STATUS_META.draft;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6, padding: "4px 10px", borderRadius: 6,
      fontSize: 11, fontWeight: 600, letterSpacing: ".04em", color: m.color,
      background: "color-mix(in oklch, " + m.color + " 12%, transparent)",
      border: "1px solid color-mix(in oklch, " + m.color + " 24%, transparent)",
    }}>
      <span style={{ width: 5, height: 5, borderRadius: 8, background: m.color }} />
      {m.label}
    </span>
  );
}

// ---------- real-image check ----------
const isRealImage = (u) => typeof u === "string" && (u.startsWith("http") || u.startsWith("data:") || u.startsWith("blob:"));

// ---------- image placeholder slot (renders a real image when src is valid) ----------
function ImageSlot({ cat, label, size = "100%", radius = 8, caption, custom = false, src }) {
  const meta = (cat && window.AppData.CATEGORIES[cat]) || { hue: 40 };
  const hasImg = isRealImage(src);
  return (
    <div style={{ width: size, position: "relative" }}>
      <div style={{
        width: "100%", aspectRatio: "1 / 1", borderRadius: radius, overflow: "hidden",
        position: "relative", display: "flex", alignItems: "center", justifyContent: "center",
        background: hasImg ? "var(--bg)" : "repeating-linear-gradient(135deg, color-mix(in srgb, var(--text) 8%, var(--surface)) 0 8px, color-mix(in srgb, var(--text) 5%, var(--surface)) 8px 16px)",
        border: "1px solid var(--border)",
      }}>
        {hasImg ? (
          <img src={src} alt={label || ""} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
        ) : (
        <span style={{
          fontFamily: "var(--mono)", fontSize: 9.5, letterSpacing: ".04em", color: "var(--faint)",
          textAlign: "center", padding: "0 8px", lineHeight: 1.4, textTransform: "lowercase",
        }}>{label || "foto producto"}</span>
        )}
        {custom && (
          <span style={{
            position: "absolute", top: 6, left: 6, fontFamily: "var(--mono)", fontSize: 8,
            fontWeight: 700, letterSpacing: ".1em", padding: "2px 5px", borderRadius: 4,
            color: "var(--gold)", background: "rgba(10,10,10,0.82)", border: "1px solid color-mix(in oklch, var(--gold) 40%, transparent)",
          }}>CUSTOM</span>
        )}
      </div>
      {caption && (
        <div style={{ fontFamily: "var(--mono)", fontSize: 9, color: "var(--muted)", marginTop: 4, lineHeight: 1.3 }}>{caption}</div>
      )}
    </div>
  );
}

// ---------- toggle switch ----------
function Toggle({ on, onChange, label }) {
  return (
    <button onClick={() => onChange(!on)} style={{
      display: "inline-flex", alignItems: "center", gap: 9, background: "none", border: "none",
      cursor: "pointer", color: "var(--text)", fontSize: 13, padding: 0, fontFamily: "var(--body)",
    }}>
      <span style={{
        width: 36, height: 20, borderRadius: 20, position: "relative", transition: "background .2s ease",
        background: on ? "var(--gold)" : "rgba(255,255,255,0.12)", flexShrink: 0,
      }}>
        <span style={{
          position: "absolute", top: 2, left: on ? 18 : 2, width: 16, height: 16, borderRadius: 16,
          background: on ? "#0A0A0A" : "#fff", transition: "left .2s ease",
        }} />
      </span>
      {label && <span style={{ color: "var(--muted)" }}>{label}</span>}
    </button>
  );
}

// ---------- small reusable button ----------
function Btn({ children, onClick, variant = "ghost", size = "md", icon, style, disabled, title }) {
  const sizes = { sm: { p: "6px 11px", fs: 12 }, md: { p: "9px 15px", fs: 13 }, lg: { p: "12px 20px", fs: 14 } };
  const s = sizes[size];
  const variants = {
    gold:   { background: "var(--gold)", color: "var(--accent-ink)", border: "1px solid var(--gold)", fontWeight: 500 },
    solid:  { background: "var(--text)", color: "var(--accent-ink)", border: "1px solid var(--text)", fontWeight: 500 },
    ghost:  { background: "var(--panel)", color: "var(--text)", border: "1px solid var(--border)", fontWeight: 500 },
    outline:{ background: "transparent", color: "var(--text)", border: "1px solid var(--border)", fontWeight: 500 },
    danger: { background: "color-mix(in oklch, var(--red) 14%, transparent)", color: "var(--red)", border: "1px solid color-mix(in oklch, var(--red) 30%, transparent)", fontWeight: 500 },
  };
  return (
    <button onClick={onClick} disabled={disabled} title={title} className="btn" style={{
      display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7, cursor: disabled ? "not-allowed" : "pointer",
      padding: s.p, fontSize: s.fs, borderRadius: 8, fontFamily: "var(--body)", opacity: disabled ? 0.45 : 1,
      transition: "transform .12s ease, filter .15s ease", whiteSpace: "nowrap", ...variants[variant], ...style,
    }}>
      {icon && <Icon name={icon} size={s.fs + 2} stroke={2} />}
      {children}
    </button>
  );
}

// ---------- card ----------
function Card({ children, style, pad = 0, onClick, hoverable }) {
  return (
    <div onClick={onClick} className={hoverable ? "hovercard" : ""} style={{
      background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 12,
      padding: pad, cursor: onClick ? "pointer" : "default", ...style,
    }}>{children}</div>
  );
}

// ---------- APU (análisis de precio unitario) ----------
// Each item carries apu = { suministro, logistica, instalacion }.
// Default split derived from sale price when a product has no explicit apu.
function defaultAPU(price) {
  const p = Number(price) || 0;
  const suministro = Math.round(p * 0.70 * 100) / 100;
  const logistica = Math.round(p * 0.10 * 100) / 100;
  const instalacion = Math.round((p - suministro - logistica) * 100) / 100;
  return { suministro, logistica, instalacion };
}
function getAPU(obj) {
  if (obj && obj.apu) return obj.apu;
  return defaultAPU(obj ? (obj.sale_price != null ? obj.sale_price : obj.unit_price) : 0);
}
// unit price the client sees = sum of components, minus logística if billed apart
function apuUnitPrice(apu, logisticaAparte) {
  const a = apu || {};
  const base = (a.suministro || 0) + (a.instalacion || 0);
  const total = logisticaAparte ? base : base + (a.logistica || 0);
  return Math.round(total * 100) / 100;
}
// line math (shared by builder + PDF so totals always match)
function itemBase(it) { return (Number(it.quantity) || 0) * (Number(it.unit_price) || 0); }
function itemLogistica(it) { return it.logistica_aparte && it.apu ? (Number(it.quantity) || 0) * (Number(it.apu.logistica) || 0) : 0; }
function itemTotal(it) { return itemBase(it) + itemLogistica(it); }
function quoteSubtotal(items) { return items.reduce((s, it) => s + itemTotal(it), 0); }
const APU_COLORS = { suministro: "#3A6FB0", logistica: "#C8924A", instalacion: "#5B9B6B" };

// ---------- styled select ----------
function Select({ value, onChange, options, style, title }) {
  return (
    <div className="select-wrap" style={style} title={title}>
      <select value={value} onChange={(e) => onChange(e.target.value)}>
        {options.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
      </select>
      <Icon name="chevron" size={13} style={{ transform: "rotate(90deg)" }} />
    </div>
  );
}

// ---------- confirm dialog ----------
function ConfirmModal({ open, title, message, confirmLabel = "Eliminar", danger = true, onConfirm, onClose }) {
  if (!open) return null;
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()} style={{ width: 400 }}>
        <div style={{ padding: "24px 24px 8px" }}>
          <h3 style={{ margin: 0, fontFamily: "var(--display)", fontSize: 19, fontWeight: 600 }}>{title}</h3>
          <p style={{ color: "var(--muted)", fontSize: 13.5, lineHeight: 1.55, margin: "10px 0 0" }}>{message}</p>
        </div>
        <div className="modal-foot">
          <div style={{ flex: 1 }} />
          <Btn variant="outline" onClick={onClose}>Cancelar</Btn>
          <Btn variant={danger ? "danger" : "gold"} icon={danger ? "trash" : "check"} onClick={() => { onConfirm(); onClose(); }}>{confirmLabel}</Btn>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  fmtMoney, fmtNum, fmtPct, marginTier, resolveItemImage, effectiveMargin, isRealImage,
  defaultAPU, getAPU, apuUnitPrice, itemBase, itemLogistica, itemTotal, quoteSubtotal, APU_COLORS,
  Icon, CatBadge, MarginPill, StatusBadge, STATUS_META, ImageSlot, Toggle, Btn, Card, Select, ConfirmModal,
});
