/* ============================================================================
   Shared UI kit for the Vietnam trip app. Built on Fluent tokens.
   All components attached to window at the bottom.
   ============================================================================ */

/* Fluent System Icon — fetched once and inlined so it inherits currentColor.
   (Cross-origin CSS masks are blocked in this runtime, so we inline the SVG.) */
const _iconCache = {};
const _ICON_SIZES = [16, 20, 24, 28, 32, 48];
function _assetSize(s) { return _ICON_SIZES.find((x) => x >= s) || 48; }
function Icon({ name, size = 20, filled = false, color = "currentColor", style = {} }) {
  const variant = filled ? "filled" : "regular";
  const want = _assetSize(size);
  // Icons are vendored locally (vendor/fluent-icons) so the app works offline.
  // Not every icon exists at every size, so cascade: requested size first, then
  // the nearest other sizes, until one resolves. No network/CDN fallback.
  const url = `${name}_${variant}_${want}`; // cache + effect key
  const [svg, setSvg] = React.useState(_iconCache[url] || null);
  React.useEffect(() => {
    if (_iconCache[url]) { setSvg(_iconCache[url]); return; }
    let alive = true;
    const clean = (txt) => txt
      .replace(/<\?xml[\s\S]*?\?>/i, "")
      .replace(/\swidth="[^"]*"/i, "")
      .replace(/\sheight="[^"]*"/i, "")
      .replace(/<svg /i, '<svg width="100%" height="100%" fill="currentColor" ');
    // Prefer the manifest of vendored sizes so we never probe a missing file
    // (avoids 404s); fall back to trying all sizes if the manifest is absent.
    const avail = window.__ICON_AVAIL && window.__ICON_AVAIL[name] && window.__ICON_AVAIL[name][variant];
    const order = (avail && avail.length)
      ? avail.slice().sort((a, b) => Math.abs(a - want) - Math.abs(b - want) || a - b)
      : _ICON_SIZES.slice().sort((a, b) => Math.abs(a - want) - Math.abs(b - want) || a - b);
    (async () => {
      for (const s of order) {
        try {
          const r = await fetch(`vendor/fluent-icons/${name}_${s}_${variant}.svg`);
          if (!r.ok) continue;
          const txt = clean(await r.text());
          _iconCache[url] = txt;
          if (alive) setSvg(txt);
          return;
        } catch (e) { /* try next size */ }
      }
    })();
    return () => { alive = false; };
  }, [url]);
  return (
    <span
      aria-hidden="true"
      style={{ display: "inline-flex", width: size, height: size, flexShrink: 0,
        color, lineHeight: 0, verticalAlign: "middle", ...style }}
      dangerouslySetInnerHTML={{ __html: svg || "" }}
    />
  );
}

/* Round avatar with initial. */
function Avatar({ person, size = 32, ring = false }) {
  return (
    <span style={{
      width: size, height: size, borderRadius: "50%", flexShrink: 0,
      background: person.color, color: "#fff",
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      fontWeight: 600, fontSize: size * 0.42, letterSpacing: "-0.01em",
      boxShadow: ring ? "0 0 0 2px var(--colorNeutralBackground1)" : "none",
      fontFamily: "var(--fontFamilyBase)",
    }}>{person.initial}</span>
  );
}

function AvatarStack({ people, size = 28 }) {
  return (
    <span style={{ display: "inline-flex" }}>
      {people.map((p, i) => (
        <span key={p.id} style={{ marginLeft: i === 0 ? 0 : -size * 0.32 }}>
          <Avatar person={p} size={size} ring />
        </span>
      ))}
    </span>
  );
}

/* Overline micro-label (Sitka-flavoured uppercase). */
function Overline({ children, color = "var(--colorNeutralForeground3)", style = {} }) {
  return (
    <div style={{
      fontSize: 11, fontWeight: 700, letterSpacing: "0.14em",
      textTransform: "uppercase", color, fontFamily: "var(--fontFamilyBase)",
      ...style,
    }}>{children}</div>
  );
}

/* Editorial serif heading (Sitka Small). */
function Serif({ children, size = 28, weight = 600, italic = false, color = "var(--colorNeutralForeground1)", style = {} }) {
  return (
    <span style={{
      fontFamily: "var(--fontFamilySerif)", fontSize: size, fontWeight: weight,
      fontStyle: italic ? "italic" : "normal", lineHeight: 1.1,
      letterSpacing: "-0.01em", color, ...style,
    }}>{children}</span>
  );
}

function Card({ children, pad = 16, style = {}, onClick, interactive = false }) {
  const [hover, setHover] = React.useState(false);
  return (
    <div
      onClick={onClick}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        background: "var(--colorNeutralBackground1)",
        border: "1px solid var(--colorNeutralStroke2)",
        borderRadius: 18, padding: pad,
        boxShadow: interactive && hover ? "var(--shadow8)" : "var(--shadow2)",
        cursor: onClick ? "pointer" : "default",
        transition: "box-shadow var(--durationNormal) var(--curveEasyEase), transform var(--durationFaster) var(--curveEasyEase)",
        transform: interactive && hover ? "translateY(-1px)" : "none",
        ...style,
      }}
    >{children}</div>
  );
}

function Chip({ children, tone = "neutral", filled = false, style = {} }) {
  const tones = {
    neutral: { bg: "var(--colorNeutralBackground3)", fg: "var(--colorNeutralForeground2)" },
    teal:    { bg: "rgba(3,131,135,0.10)", fg: "var(--color-darkTeal)" },
    amber:   { bg: "rgba(234,163,0,0.16)", fg: "var(--color-brass)" },
    pumpkin: { bg: "rgba(202,80,16,0.12)", fg: "var(--color-pumpkin)" },
    green:   { bg: "var(--colorStatusSuccessBackground1)", fg: "var(--colorStatusSuccessForeground1)" },
  };
  const t = tones[tone] || tones.neutral;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 4,
      padding: "3px 9px", borderRadius: 999, fontSize: 11.5, fontWeight: 600,
      background: filled ? t.fg : t.bg, color: filled ? "#fff" : t.fg,
      whiteSpace: "nowrap", letterSpacing: "0.01em", ...style,
    }}>{children}</span>
  );
}

/* Primary / secondary button. */
function Btn({ children, kind = "primary", icon, onClick, full = false, size = "md", style = {} }) {
  const [active, setActive] = React.useState(false);
  const pads = size === "sm" ? "7px 12px" : "11px 18px";
  const fs = size === "sm" ? 13 : 14.5;
  const kinds = {
    primary: { background: "var(--color-teal)", color: "#fff", border: "1px solid transparent" },
    dark:    { background: "var(--color-darkTeal)", color: "#fff", border: "1px solid transparent" },
    amber:   { background: "var(--color-marigold)", color: "#3a2c00", border: "1px solid transparent" },
    ghost:   { background: "var(--colorNeutralBackground1)", color: "var(--colorNeutralForeground1)", border: "1px solid var(--colorNeutralStroke1)" },
    soft:    { background: "rgba(3,131,135,0.10)", color: "var(--color-darkTeal)", border: "1px solid transparent" },
  };
  const k = kinds[kind] || kinds.primary;
  return (
    <button
      onClick={onClick}
      onMouseDown={() => setActive(true)}
      onMouseUp={() => setActive(false)}
      onMouseLeave={() => setActive(false)}
      style={{
        ...k, padding: pads, fontSize: fs, fontWeight: 600,
        fontFamily: "var(--fontFamilyBase)", borderRadius: 12,
        display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7,
        width: full ? "100%" : "auto", cursor: "pointer",
        transform: active ? "scale(0.97)" : "scale(1)",
        transition: "transform var(--durationFaster) var(--curveEasyEase), filter var(--durationFaster)",
        filter: active ? "brightness(0.94)" : "none",
        ...style,
      }}
    >
      {icon && <Icon name={icon} size={18} color="currentColor" />}
      {children}
    </button>
  );
}

/* One-tap Google Maps pill. */
function MapsLink({ query, lat, lng, label = "Navigate", size = "sm" }) {
  return (
    <a href={window.TRIP.dirUrl(query, lat, lng)} target="_blank" rel="noopener noreferrer"
       onClick={(e) => e.stopPropagation()}
       style={{ textDecoration: "none" }}>
      <span style={{
        display: "inline-flex", alignItems: "center", gap: 5,
        padding: size === "sm" ? "5px 10px" : "8px 14px",
        borderRadius: 999, background: "rgba(3,131,135,0.10)",
        color: "var(--color-darkTeal)", fontSize: size === "sm" ? 12 : 13.5,
        fontWeight: 600, fontFamily: "var(--fontFamilyBase)", whiteSpace: "nowrap",
      }}>
        <Icon name="location" size={size === "sm" ? 14 : 16} filled color="var(--color-teal)" />
        {label}
      </span>
    </a>
  );
}

/* Segmented control (sub-tabs). */
function SegTabs({ tabs, value, onChange }) {
  return (
    <div style={{
      display: "flex", gap: 3, padding: 3, borderRadius: 12,
      background: "var(--colorNeutralBackground3)", margin: "0 0 14px",
    }}>
      {tabs.map((t) => {
        const on = t.id === value;
        return (
          <button key={t.id} onClick={() => onChange(t.id)} style={{
            flex: 1, padding: "8px 6px", border: "none", borderRadius: 9,
            background: on ? "var(--colorNeutralBackground1)" : "transparent",
            color: on ? "var(--colorNeutralForeground1)" : "var(--colorNeutralForeground3)",
            fontWeight: 600, fontSize: 13.5, fontFamily: "var(--fontFamilyBase)",
            cursor: "pointer", boxShadow: on ? "var(--shadow2)" : "none",
            transition: "all var(--durationFast) var(--curveEasyEase)",
            display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6,
          }}>{t.icon && <Icon name={t.icon} size={16} filled={on} color={on ? "var(--color-teal)" : "currentColor"} />}{t.label}</button>
        );
      })}
    </div>
  );
}

function Progress({ value, max = 1, color = "var(--color-teal)", height = 8, bg = "var(--colorNeutralBackground4)" }) {
  const pct = max > 0 ? Math.max(0, Math.min(1, value / max)) * 100 : 0;
  return (
    <div style={{ height, borderRadius: 999, background: bg, overflow: "hidden" }}>
      <div style={{
        width: pct + "%", height: "100%", background: color, borderRadius: 999,
        transition: "width var(--durationSlow) var(--curveEasyEase)",
      }} />
    </div>
  );
}

/* A soft "stamp" badge used on the recap / passport vibe. */
function Stamp({ children, color = "var(--color-pumpkin)", rotate = -8 }) {
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      padding: "6px 12px", border: `2px solid ${color}`, color,
      borderRadius: 8, fontWeight: 800, fontSize: 12, letterSpacing: "0.12em",
      textTransform: "uppercase", transform: `rotate(${rotate}deg)`,
      fontFamily: "var(--fontFamilyBase)", opacity: 0.9,
    }}>{children}</span>
  );
}

Object.assign(window, {
  Icon, Avatar, AvatarStack, Overline, Serif, Card, Chip, Btn, MapsLink, SegTabs, Progress, Stamp,
});
