// components.jsx — shared marketplace components

const { useState, useEffect, useMemo, useRef, useCallback } = React;

// ────────────────────────────────────────────────────────────────────
// Skill avatar — gradient tile w/ initials
function SkillAvatar({ skill, size = 36, radius }) {
  const [a, b] = skill.color || ["#5a3fa9", "#8c75d0"];
  return (
    <div className="savatar" style={{
      width: size, height: size,
      borderRadius: radius || (size >= 56 ? 12 : size >= 40 ? 10 : 8),
      background: `linear-gradient(135deg, ${a}, ${b})`,
      color: "#fff",
      fontSize: size <= 28 ? 11 : size <= 40 ? 13 : size <= 56 ? 16 : 22,
    }}>
      {skill.glyph}
    </div>
  );
}

// Trust badge — display-only chip with icon
const BADGE_DEFS = {
  verified: { label: "Verified", cls: "badge-verified", icon: "Verified", title: "Author identity confirmed by IrisGo." },
  secure:   { label: "Security reviewed", cls: "badge-secure", icon: "ShieldCheck", title: "Static + behavioral review passed within 30 days." },
  team:     { label: "Team-approved", cls: "badge-team", icon: "Users", title: "Approved for use in your workspace." },
  new:      { label: "New", cls: "badge-new", icon: "Sparkle", title: "Published in the last 14 days." },
  popular:  { label: "Popular", cls: "badge-popular", icon: "Trend", title: "High install velocity this month." },
  deprecated:{ label:"Deprecated", cls: "badge-deprecated", icon: "X", title: "No longer maintained." },
  updated:  { label: "Updated", cls: "badge-updated", icon: "Clock", title: "Updated within 7 days." },
};
function Badge({ kind, compact, title }) {
  const def = BADGE_DEFS[kind];
  if (!def) return null;
  const Glyph = I[def.icon];
  return (
    <span className={`badge ${def.cls}`} title={title || def.title}>
      {Glyph && <Glyph size={11} />}
      {!compact && <span>{def.label}</span>}
    </span>
  );
}

// Star rating
function Stars({ value = 0, size = 12 }) {
  const full = Math.round(value);
  return (
    <span className="row gap-1" aria-label={`Rated ${value} out of 5`}>
      {[0,1,2,3,4].map(i => (
        i < full
          ? <I.Star key={i} size={size} style={{ color: "#caa204" }} />
          : <I.StarO key={i} size={size} style={{ color: "var(--ink-5)" }} />
      ))}
    </span>
  );
}

// ────────────────────────────────────────────────────────────────────
// Skill card — primary listing component
function SkillCard({ skill, onOpen, onInstall, dense, installed }) {
  const main = (skill.badges || []).slice(0, 3);
  return (
    <button className="card hoverable unstyled" onClick={() => onOpen(skill.id)}
      style={{
        padding: dense ? 14 : 18,
        display: "flex", flexDirection: "column", gap: 12,
        height: "100%", textAlign: "left",
      }}>
      <div className="row gap-3" style={{ alignItems: "flex-start" }}>
        <SkillAvatar skill={skill} size={dense ? 36 : 40} />
        <div className="grow col gap-1">
          <div className="row between gap-2" style={{ alignItems: "flex-start" }}>
            <div className="col" style={{ minWidth: 0 }}>
              <div style={{ font: "600 14.5px/1.25 var(--font-display)", color: "var(--ink)", letterSpacing: "-0.005em" }}>
                {skill.name}
              </div>
              <div className="meta" style={{ marginTop: 2 }}>
                {skill.author}{skill.author_verified && <span title="Verified author" style={{ color: "var(--blue-600)", marginLeft: 4 }}>•</span>}
              </div>
            </div>
          </div>
        </div>
      </div>
      <div className="body-sm" style={{ color: "var(--ink-2)", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }}>
        {skill.one_liner}
      </div>
      <div className="row gap-2 wrap" style={{ marginTop: "auto" }}>
        {main.map(b => <Badge key={b} kind={b} compact={main.length > 2} />)}
      </div>
      <div className="row between gap-2" style={{ paddingTop: 10, borderTop: "1px solid var(--line-soft)" }}>
        <div className="meta row gap-2" style={{ minWidth: 0 }}>
          <span>{skill.installs_label} installs</span>
          <span style={{ color: "var(--ink-5)" }}>·</span>
          <span>Updated {skill.last_updated}</span>
        </div>
        <span
          role="button"
          className={`btn btn-sm ${installed ? "" : "btn-primary"}`}
          onClick={(e) => { e.stopPropagation(); installed ? onOpen(skill.id) : onInstall(skill); }}
        >
          {installed ? "Installed" : "Install"}
        </span>
      </div>
    </button>
  );
}

// Compact row card — for trending row, library rows
function SkillRow({ skill, onOpen, onInstall, installed, showMeta = true }) {
  return (
    <div className="card hoverable" onClick={() => onOpen(skill.id)}
      style={{ padding: 14, display: "flex", alignItems: "center", gap: 14, cursor: "pointer" }}>
      <SkillAvatar skill={skill} size={36} />
      <div className="grow col" style={{ minWidth: 0 }}>
        <div className="row gap-2" style={{ alignItems: "baseline" }}>
          <div style={{ font: "600 14px/1.2 var(--font-display)" }}>{skill.name}</div>
          <span className="meta">{skill.author}</span>
        </div>
        <div className="body-sm" style={{ color: "var(--ink-2)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
          {skill.one_liner}
        </div>
      </div>
      {showMeta && (
        <div className="row gap-3" style={{ flex: "0 0 auto" }}>
          <div className="meta">{skill.installs_label}</div>
          {(skill.badges || []).slice(0, 2).map(b => <Badge key={b} kind={b} compact />)}
        </div>
      )}
      <span
        role="button"
        className={`btn btn-sm ${installed ? "" : "btn-primary"}`}
        onClick={(e) => { e.stopPropagation(); installed ? onOpen(skill.id) : onInstall(skill); }}
      >
        {installed ? "Installed" : "Install"}
      </span>
    </div>
  );
}

// Filter chip group
function FilterChips({ value, options, onChange, multi }) {
  return (
    <div className="row gap-2 wrap">
      {options.map(opt => {
        const k = typeof opt === "string" ? opt : opt.value;
        const label = typeof opt === "string" ? opt : opt.label;
        const active = multi ? (value || []).includes(k) : value === k;
        return (
          <button key={k} className={`chip ${active ? "active" : ""}`} onClick={(e) => {
            e.preventDefault();
            if (multi) {
              const set = new Set(value || []);
              if (set.has(k)) set.delete(k); else set.add(k);
              onChange([...set]);
            } else {
              onChange(active ? null : k);
            }
          }}>
            {label}
          </button>
        );
      })}
    </div>
  );
}

// Section header
function SectionHead({ title, subtitle, action, icon }) {
  return (
    <div className="section-head">
      <div className="col gap-1">
        <div className="row gap-2">
          {icon && <span style={{ color: "var(--ink-3)" }}>{icon}</span>}
          <h2 className="h3" style={{ margin: 0 }}>{title}</h2>
        </div>
        {subtitle && <div className="body-sm text-3">{subtitle}</div>}
      </div>
      {action}
    </div>
  );
}

// Reason string for recommendations
function ReasonChip({ icon, children }) {
  const Glyph = icon ? I[icon] : null;
  return (
    <span className="meta row gap-1" style={{
      background: "var(--iris-50)", color: "var(--iris-700)",
      padding: "4px 8px", borderRadius: 999, fontSize: 11.5, fontWeight: 500,
    }}>
      {Glyph && <Glyph size={11} />}
      {children}
    </span>
  );
}

// Top bar
function IrisMark({ variant = "green", size = 26 }) {
  const src = variant === "lime"
    ? "assets/IrisGo-Logo-Lime.png"
    : "assets/IrisGo-Logo-Green.png";
  // The brand asset is a horizontal lockup (mark + wordmark). For UI use we
  // crop to just the mark on the left ~25% of the image via object-fit cover.
  return (
    <span style={{
      display: "inline-block", width: size, height: size,
      backgroundImage: `url(${src})`,
      backgroundSize: "auto 100%",
      backgroundRepeat: "no-repeat",
      backgroundPosition: "left center",
      // Mark sits in the leftmost portion of the lockup; clip the wordmark.
      // Aspect of source ~5495×1392 ≈ 3.95:1; mark occupies ~the first 1.05:1
      // square. We size the bg to height=size and let bg-position+width crop.
    }} aria-label="IrisGo" />
  );
}

function TopBar({ route, onNav, onOpenSearch, query }) {
  const links = [
    { id: "home", label: "Discover" },
    { id: "browse", label: "Browse" },
    { id: "teams", label: "Teams" },
    { id: "library", label: "Library" },
    { id: "studio", label: "Studio" },
  ];
  return (
    <header className="topbar">
      <div className="topbar-inner">
        <a className="brand" onClick={(e) => { e.preventDefault(); onNav("home"); }} href="#">
          <span className="brand-mark"><IrisMark variant="green" size={26} /></span>
          IrisGo
        </a>
        <nav className="nav-links">
          {links.map(l => (
            <a key={l.id} className={`nav-link ${route === l.id ? "active" : ""}`}
               href="#" onClick={(e) => { e.preventDefault(); onNav(l.id); }}>
              {l.label}
            </a>
          ))}
        </nav>
        <div className="grow" />
        <button className="search-trigger" onClick={onOpenSearch}>
          <I.Search size={14} />
          <span>{query || "Search skills, authors, tasks…"}</span>
          <kbd>⌘K</kbd>
        </button>
        <button className="icon-btn" title="Notifications">
          <I.Sparkle size={16} />
        </button>
        <span className="avatar">JL</span>
      </div>
    </header>
  );
}

// Spotlight / command-K search dialog
function CommandSearch({ open, onClose, onPick }) {
  const [q, setQ] = useState("");
  const inputRef = useRef(null);
  useEffect(() => { if (open) setTimeout(() => inputRef.current?.focus(), 30); }, [open]);
  useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape" && open) onClose();
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  const results = useMemo(() => {
    const t = q.trim().toLowerCase();
    if (!t) return SKILLS.slice(0, 6);
    return SKILLS.filter(s =>
      s.name.toLowerCase().includes(t) ||
      s.one_liner.toLowerCase().includes(t) ||
      s.category.toLowerCase().includes(t) ||
      s.author.toLowerCase().includes(t) ||
      (s.use_cases || []).some(u => u.includes(t))
    ).slice(0, 8);
  }, [q]);
  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, background: "rgba(15,17,21,0.32)",
      zIndex: 100, display: "flex", justifyContent: "center", paddingTop: 96,
      backdropFilter: "blur(2px)",
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: 620, maxWidth: "90vw", maxHeight: "70vh",
        background: "var(--bg)", borderRadius: 14, boxShadow: "var(--sh-pop)",
        display: "flex", flexDirection: "column", overflow: "hidden",
      }}>
        <div className="row gap-3" style={{ padding: "14px 16px", borderBottom: "1px solid var(--line)" }}>
          <I.Search size={16} style={{ color: "var(--ink-3)" }} />
          <input ref={inputRef} value={q} onChange={(e) => setQ(e.target.value)}
            placeholder="Search skills, authors, tasks…"
            style={{
              flex: 1, border: "none", outline: "none", background: "transparent",
              font: "400 16px/1 var(--font-sans)", color: "var(--ink)",
            }} />
          <kbd style={{ font: "500 11px/1 var(--font-mono)", color: "var(--ink-3)", border: "1px solid var(--line)", padding: "3px 6px", borderRadius: 4 }}>esc</kbd>
        </div>
        <div className="scroll-thin" style={{ overflow: "auto", padding: 8 }}>
          {!q.trim() && (
            <div className="eyebrow" style={{ padding: "8px 10px" }}>Suggested</div>
          )}
          {results.length === 0 && (
            <div className="body-sm text-3" style={{ padding: 18 }}>No skills match “{q}”. Try a task like “review PR” or “summarize CSV”.</div>
          )}
          {results.map(s => (
            <button key={s.id} className="unstyled" onClick={() => { onPick(s.id); onClose(); }} style={{
              display: "flex", gap: 12, padding: 10, borderRadius: 8, width: "100%",
              alignItems: "center",
            }}
              onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-muted)"}
              onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
            >
              <SkillAvatar skill={s} size={28} />
              <div className="col grow" style={{ minWidth: 0 }}>
                <div className="row gap-2" style={{ alignItems: "baseline" }}>
                  <span style={{ font: "500 13.5px/1.2 var(--font-sans)" }}>{s.name}</span>
                  <span className="meta">· {s.author}</span>
                </div>
                <div className="meta" style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{s.one_liner}</div>
              </div>
              <span className="tag">{s.category}</span>
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

window.IrisMark = IrisMark;
window.SkillAvatar = SkillAvatar;
window.Badge = Badge;
window.Stars = Stars;
window.SkillCard = SkillCard;
window.SkillRow = SkillRow;
window.FilterChips = FilterChips;
window.SectionHead = SectionHead;
window.ReasonChip = ReasonChip;
window.TopBar = TopBar;
window.CommandSearch = CommandSearch;
