// ============================================
// Reliq — Trust Registry (public profiles)
// Increment 7. Reuses Trust Score data; mock-driven in the prototype.
// ============================================


const KIND_LABEL = { COMPANY:"Company", PRODUCT:"Product", API:"API", WEBSITE:"Website" };
const scoreColor = (s) => s >= 75 ? "var(--teal)" : s >= 60 ? "var(--yellow)" : "var(--red)";

const TrustBadgePills = ({ badges }) => {
  const list = [];
  if (badges.trustReady)       list.push("Trust-ready");
  if (badges.agentReady)       list.push("Agent-ready");
  if (badges.integrationReady) list.push("Integration-ready");
  if (list.length === 0) return null;
  return (
    <div style={{display:"flex", gap:6, flexWrap:"wrap", marginTop:10}}>
      {list.map(label => (
        <span key={label} style={{
          fontFamily:"var(--font-mono)", fontSize:9.5, fontWeight:600, letterSpacing:"0.04em",
          padding:"2px 7px", borderRadius:4, color:"var(--teal)", background:"var(--teal-bg)",
          border:"1px solid rgba(0,212,170,0.25)", textTransform:"uppercase",
        }}>{label}</span>
      ))}
    </div>
  );
};

// ── Trust history + score movement (Increment 8) ─────────────────
const DIRECTION_META = {
  up:   { arrow:"▲", color:"var(--teal)" },
  down: { arrow:"▼", color:"var(--red)" },
  flat: { arrow:"▬", color:"var(--fg-3)" },
};
const fmtMovement = (n) => n == null ? "—" : (n > 0 ? "+" + n : String(n));

const TrustHistory = ({ trend, history }) => {
  if (!trend && (!history || history.length === 0)) return null;
  const dir = DIRECTION_META[(trend && trend.direction) || "flat"];
  const maxOverall = Math.max(1, ...(history || []).map(h => h.overall || 0));
  return (
    <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"16px 18px", marginBottom:18}}>
      <div style={{fontWeight:600, fontSize:13, color:"var(--fg-0)", marginBottom:12}}>Trust history</div>
      {trend && (
        <div style={{display:"flex", gap:18, flexWrap:"wrap", marginBottom:14}}>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>Current</div>
            <div style={{fontFamily:"var(--font-mono)", fontSize:18, fontWeight:700, color:scoreColor(trend.current)}}>
              {trend.current ?? "—"} <span style={{color:dir.color, fontSize:12}}>{dir.arrow}</span>
            </div>
          </div>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>Previous</div>
            <div style={{fontFamily:"var(--font-mono)", fontSize:18, fontWeight:700, color:"var(--fg-1)"}}>{trend.previous ?? "—"}</div>
          </div>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>30-day</div>
            <div style={{fontFamily:"var(--font-mono)", fontSize:18, fontWeight:700, color:trend.movement30d > 0 ? "var(--teal)" : trend.movement30d < 0 ? "var(--red)" : "var(--fg-2)"}}>{fmtMovement(trend.movement30d)}</div>
          </div>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>90-day</div>
            <div style={{fontFamily:"var(--font-mono)", fontSize:18, fontWeight:700, color:trend.movement90d > 0 ? "var(--teal)" : trend.movement90d < 0 ? "var(--red)" : "var(--fg-2)"}}>{fmtMovement(trend.movement90d)}</div>
          </div>
        </div>
      )}
      {history && history.length > 0 && (
        <div style={{display:"flex", flexDirection:"column", gap:6}}>
          {history.map((h, i) => (
            <div key={i} style={{display:"flex", alignItems:"center", gap:10}}>
              <div className="mono" style={{fontSize:11, color:"var(--fg-3)", minWidth:78}}>{h.capturedAt}</div>
              <div style={{flex:1, height:6, background:"var(--bg-1)", borderRadius:3, overflow:"hidden"}}>
                <div style={{width:((h.overall || 0) / maxOverall * 100) + "%", height:"100%", background:scoreColor(h.overall)}} />
              </div>
              <div className="mono" style={{fontSize:12, fontWeight:600, color:scoreColor(h.overall), minWidth:26, textAlign:"right"}}>{h.overall}</div>
              <div className="mono" style={{fontSize:10.5, color:"var(--fg-3)", minWidth:74, textAlign:"right"}}>{h.grade}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

// ── Trust Monitoring + recent changes (Increment A4) ─────────────
const CHANGE_TONE = {
  up:    "var(--teal)",
  down:  "var(--red)",
  alert: "var(--red)",
};

const TrustMonitoring = ({ monitoring, changes }) => {
  const m = monitoring || { enabled:false };
  const status = window.monitoringStatusLabel(m);
  return (
    <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"16px 18px", marginBottom:18}}>
      <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", gap:10, marginBottom:12}}>
        <div style={{fontWeight:600, fontSize:13, color:"var(--fg-0)"}}>Trust monitoring</div>
        <span style={{
          fontFamily:"var(--font-mono)", fontSize:10, fontWeight:600, letterSpacing:"0.04em", textTransform:"uppercase",
          padding:"2px 8px", borderRadius:4,
          color: m.enabled ? "var(--teal)" : "var(--fg-3)",
          background: m.enabled ? "var(--teal-bg)" : "transparent",
          border: m.enabled ? "1px solid rgba(0,212,170,0.25)" : "1px solid var(--line-2)",
        }}>{m.enabled ? "Active" : "Off"}</span>
      </div>
      {m.enabled ? (
        <div style={{display:"flex", gap:18, flexWrap:"wrap", marginBottom:14}}>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>Frequency</div>
            <div style={{fontSize:13, color:"var(--fg-1)", textTransform:"capitalize"}}>{m.frequency || "weekly"}</div>
          </div>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>Last check</div>
            <div className="mono" style={{fontSize:13, color:"var(--fg-1)"}}>{m.lastMonitoredAt || "—"}</div>
          </div>
          <div>
            <div className="mono" style={{fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:"0.04em"}}>Next check</div>
            <div className="mono" style={{fontSize:13, color:"var(--fg-1)"}}>{m.nextMonitorAt || "—"}</div>
          </div>
        </div>
      ) : (
        <div style={{fontSize:12, color:"var(--fg-2)", marginBottom:6}}>{status} — enable monitoring to track score and badge changes over time.</div>
      )}
      {changes && changes.length > 0 && (
        <div>
          <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", margin:"4px 0 8px"}}>Recent changes</div>
          <div style={{display:"flex", flexDirection:"column", gap:7}}>
            {changes.map((ch, i) => {
              const d = window.describeChange(ch);
              return (
                <div key={i} style={{display:"flex", alignItems:"center", gap:8}}>
                  <span style={{color:CHANGE_TONE[d.tone] || "var(--fg-2)", fontSize:12, width:14, textAlign:"center"}}>{d.symbol}</span>
                  <span style={{flex:1, fontSize:12.5, color:"var(--fg-1)"}}>{d.text}</span>
                  <span className="mono" style={{fontSize:10.5, color:"var(--fg-3)"}}>{ch.detectedAt}</span>
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
};

// ── Embeddable Trust Badges (Increment 9) ────────────────────────
const BADGE_API = "https://api.reliq.dev";
const BADGE_SITE = "https://reliq.dev";

// A faux shields-style pill that mirrors the server-rendered SVG badge.
const BadgePill = ({ label, message, color }) => (
  <span style={{display:"inline-flex", height:20, borderRadius:3, overflow:"hidden", fontFamily:"Verdana, var(--font-mono)", fontSize:11, lineHeight:"20px"}}>
    <span style={{background:"#24292f", color:"#fff", padding:"0 8px"}}>{label}</span>
    <span style={{background:color, color:"#fff", padding:"0 8px"}}>{message}</span>
  </span>
);

const TrustBadges = ({ slug, badges }) => {
  const [copied, setCopied] = React.useState("");
  if (!badges || badges.length === 0) return null;

  const copy = (text, key) => {
    try { navigator.clipboard?.writeText(text); } catch (e) { /* noop */ }
    setCopied(key);
    window.reliqToast?.info("Copied embed snippet");
    setTimeout(() => setCopied(""), 1500);
  };

  const profileUrl = `${BADGE_SITE}/registry/${slug}`;
  const svgUrlFor = (type) => `${BADGE_API}/v1/registry/${slug}/badge/${type}.svg`;

  return (
    <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"16px 18px", marginBottom:18}}>
      <div style={{fontWeight:600, fontSize:13, color:"var(--fg-0)", marginBottom:4}}>Embed your Trust Badges</div>
      <div style={{fontSize:12, color:"var(--fg-2)", marginBottom:14, lineHeight:1.5}}>
        Add a live Reliq badge to your site or README. Each badge links back to this profile and reflects your current Trust Score.
      </div>
      <div style={{display:"flex", flexDirection:"column", gap:14}}>
        {badges.map((b) => {
          const svgUrl = svgUrlFor(b.type);
          const html = `<a href="${profileUrl}" target="_blank" rel="noopener"><img src="${svgUrl}" alt="${b.label}" /></a>`;
          const markdown = `[![${b.label}](${svgUrl})](${profileUrl})`;
          return (
            <div key={b.type} style={{display:"flex", alignItems:"center", gap:12}}>
              <div style={{display:"flex", alignItems:"center", gap:10, minWidth:0, flex:1}}>
                <BadgePill label={b.label.replace(/^Reliq /, "reliq ").toLowerCase()} message={b.message} color={b.color} />
                {!b.earned && <span className="mono" style={{fontSize:10, color:"var(--fg-3)", whiteSpace:"nowrap"}}>not yet earned</span>}
              </div>
              <div style={{display:"flex", gap:6, flexShrink:0}}>
                <button className="btn btn-sm btn-ghost" onClick={() => copy(html, b.type + "-html")}>
                  {copied === b.type + "-html" ? "Copied" : "Copy HTML"}
                </button>
                <button className="btn btn-sm btn-ghost" onClick={() => copy(markdown, b.type + "-md")}>
                  {copied === b.type + "-md" ? "Copied" : "Copy Markdown"}
                </button>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};

// ── Discovery dataset (mirrors GET /v1/registry/discover items) ───
// Mock-driven in the prototype; same shape the Discovery API returns.

const SORT_OPTIONS = [
  { value:"trust",    label:"Trust score" },
  { value:"agent",    label:"Agent score" },
  { value:"api",      label:"API score" },
  { value:"docs",     label:"Docs score" },
  { value:"newest",   label:"Newest" },
  { value:"movement", label:"Strongest movement" },
];
const KIND_OPTIONS = [
  { value:"",        label:"All kinds" },
  { value:"COMPANY", label:"Company" },
  { value:"PRODUCT", label:"Product" },
  { value:"API",     label:"API" },
  { value:"WEBSITE", label:"Website" },
];
const MIN_TRUST_OPTIONS = [
  { value:0,  label:"Any score" },
  { value:60, label:"60+" },
  { value:75, label:"75+" },
  { value:85, label:"85+" },
];
const BADGE_FILTERS = [
  { key:"trust-ready",       label:"Trust-ready" },
  { key:"agent-ready",       label:"Agent-ready" },
  { key:"integration-ready", label:"Integration-ready" },
];
const DIRECTION_OPTIONS = [
  { value:"",     label:"Any trend" },
  { value:"up",   label:"Improving" },
  { value:"flat", label:"Steady" },
  { value:"down", label:"Declining" },
];

const selStyle = { padding:"7px 9px", borderRadius:8, border:"1px solid var(--line-2)", background:"var(--bg-1)", color:"var(--fg-0)", fontSize:12 };

// ── Profile card ──────────────────────────────────────────────────
const ProfileCard = ({ profile, go }) => {
  const c = window.toCardModel(profile);
  const dir = DIRECTION_META[c.trend.direction] || DIRECTION_META.flat;
  return (
    <div data-testid="profile-card" onClick={() => go("/registry/" + c.slug)} style={{
      display:"flex", flexDirection:"column", gap:8, padding:"14px 16px", cursor:"pointer",
      background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, minWidth:0,
    }}>
      <div style={{display:"flex", alignItems:"flex-start", gap:12}}>
        <div style={{flex:1, minWidth:0}}>
          <div style={{display:"flex", alignItems:"center", gap:8}}>
            <span style={{fontWeight:600, fontSize:14, color:"var(--fg-0)"}}>{c.name}</span>
            <span className="mono" style={{fontSize:9.5, color:"var(--fg-3)", border:"1px solid var(--line-2)", borderRadius:4, padding:"1px 5px"}}>{c.kindLabel}</span>
          </div>
          <div className="mono" style={{fontSize:11, color:"var(--fg-3)", marginTop:2}}>{c.grade} · /registry/{c.slug}</div>
        </div>
        <div style={{textAlign:"right", flexShrink:0}}>
          <div style={{fontFamily:"var(--font-mono)", fontSize:22, fontWeight:700, lineHeight:1, color:c.trustScore == null ? "var(--fg-3)" : scoreColor(c.trustScore)}}>{c.trustScore == null ? "—" : c.trustScore}</div>
          <div className="mono" style={{fontSize:10, color:dir.color, marginTop:3}}>{dir.arrow} {fmtMovement(c.trend.movement30d)}</div>
        </div>
      </div>
      <TrustBadgePills badges={c.badges} />
      <div style={{fontSize:12, color:"var(--fg-2)", lineHeight:1.5}}>{c.summary}</div>
      <div className="mono" style={{fontSize:10, color:"var(--fg-3)"}}>Last verified {c.lastVerified || "—"}</div>
    </div>
  );
};

const CardGrid = ({ profiles, go }) => (
  <div style={{display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(280px, 1fr))", gap:12}}>
    {profiles.map(p => <ProfileCard key={p.slug} profile={p} go={go} />)}
  </div>
);

const CategorySection = ({ title, subtitle, profiles, go }) => {
  if (!profiles || profiles.length === 0) return null;
  return (
    <div style={{marginBottom:28}}>
      <div style={{display:"flex", alignItems:"baseline", gap:10, marginBottom:12}}>
        <h2 style={{fontFamily:"var(--font-display)", fontSize:16, fontWeight:700, color:"var(--fg-0)", margin:0}}>{title}</h2>
        {subtitle && <span className="mono" style={{fontSize:11, color:"var(--fg-3)"}}>{subtitle}</span>}
      </div>
      <CardGrid profiles={profiles} go={go} />
    </div>
  );
};

// ── Filter + sort controls ────────────────────────────────────────
const DiscoveryControls = ({ state, set, onClear, active }) => {
  const toggleBadge = (key) => {
    const has = state.badges.includes(key);
    set({ badges: has ? state.badges.filter(b => b !== key) : [...state.badges, key] });
  };
  return (
    <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"14px 16px", marginBottom:24}}>
      <input
        type="search" value={state.q} onChange={e => set({ q: e.target.value })} placeholder="Search the registry…"
        style={{width:"100%", padding:"10px 12px", borderRadius:8, border:"1px solid var(--line-2)", background:"var(--bg-1)", color:"var(--fg-0)", fontSize:13, marginBottom:12, boxSizing:"border-box"}}
      />
      <div style={{display:"flex", flexWrap:"wrap", gap:10, alignItems:"center"}}>
        <select aria-label="Kind" value={state.kind} onChange={e => set({ kind: e.target.value })} style={selStyle}>
          {KIND_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
        <select aria-label="Minimum trust score" value={state.minTrust} onChange={e => set({ minTrust: Number(e.target.value) })} style={selStyle}>
          {MIN_TRUST_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
        <select aria-label="Trend direction" value={state.direction} onChange={e => set({ direction: e.target.value })} style={selStyle}>
          {DIRECTION_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
        <div style={{display:"flex", alignItems:"center", gap:6, marginLeft:"auto"}}>
          <span className="mono" style={{fontSize:11, color:"var(--fg-3)"}}>Sort</span>
          <select aria-label="Sort by" value={state.sort} onChange={e => set({ sort: e.target.value })} style={selStyle}>
            {SORT_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>
        </div>
      </div>
      <div style={{display:"flex", flexWrap:"wrap", gap:6, marginTop:12, alignItems:"center"}}>
        {BADGE_FILTERS.map(b => {
          const on = state.badges.includes(b.key);
          return (
            <button key={b.key} onClick={() => toggleBadge(b.key)} style={{
              fontFamily:"var(--font-mono)", fontSize:10, fontWeight:600, letterSpacing:"0.03em", cursor:"pointer",
              padding:"4px 9px", borderRadius:5, textTransform:"uppercase",
              color: on ? "var(--teal)" : "var(--fg-3)",
              background: on ? "var(--teal-bg)" : "transparent",
              border: on ? "1px solid rgba(0,212,170,0.35)" : "1px solid var(--line-2)",
            }}>{b.label}</button>
          );
        })}
        {active && (
          <button onClick={onClear} style={{...selStyle, cursor:"pointer", marginLeft:"auto", fontSize:11}}>Clear filters</button>
        )}
      </div>
    </div>
  );
};

// ── Registry home (discovery experience) — backend-driven ─────────
const DEFAULT_DISCOVERY = { q:"", kind:"", minTrust:0, direction:"", badges:[], sort:"trust" };
const PAGE_SIZE = 12;

// Map registry-search summary rows → the card shape (presentation only).
const normalizeSummaryCard = (s) => ({
  name: s.name, slug: s.slug, kind: s.kind,
  trustScore: s.overallScore != null ? s.overallScore : null, grade: s.grade,
  lastVerified: s.lastScanAt || null, badges: {}, trend: {}, pillars: {},
});

const buildDiscoverParams = (state, extra) => ({
  kind: state.kind || undefined,
  minTrust: state.minTrust > 0 ? state.minTrust : undefined,
  direction: state.direction || undefined,
  badges: state.badges,
  sort: state.sort,
  limit: PAGE_SIZE,
  ...(extra || {}),
});

const LoadBox = ({ children, testid }) => (
  <div data-testid={testid} style={{padding:"44px 20px", textAlign:"center", color:"var(--fg-3)", fontSize:13, background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10}}>{children}</div>
);

const RegistryIndex = ({ go }) => {
  const [state, setState] = React.useState(DEFAULT_DISCOVERY);
  const [results, setResults] = React.useState({ items: [], hasMore: false, nextCursor: null, matched: 0 });
  const [cats, setCats] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [reloadKey, setReloadKey] = React.useState(0);

  const active = window.hasActiveQuery(state);
  const set = (patch) => setState(s => ({ ...s, ...patch }));
  const clear = () => setState(DEFAULT_DISCOVERY);
  const retry = () => setReloadKey(k => k + 1);
  const stateKey = JSON.stringify(state);

  React.useEffect(() => {
    let cancelled = false;
    setLoading(true); setError(null);
    (async () => {
      try {
        if (active) {
          let resp;
          if (state.q && state.q.trim()) {
            const r = await window.reliqRegistryApi.search({ q: state.q.trim(), kind: state.kind || undefined, limit: PAGE_SIZE });
            resp = { items: (r.profiles||[]).map(normalizeSummaryCard), hasMore: false, nextCursor: null, matched: (r.profiles||[]).length };
          } else {
            const r = await window.reliqRegistryApi.discover(buildDiscoverParams(state));
            resp = { items: r.profiles||[], hasMore: !!r.hasMore, nextCursor: r.nextCursor||null, matched: r.count ?? (r.profiles||[]).length };
          }
          if (!cancelled) setResults(resp);
        } else {
          const [top, agent, moving, recent, apis, products] = await Promise.all([
            window.reliqRegistryApi.discoverTop({ sort:"trust", limit:6 }),
            window.reliqRegistryApi.discoverTop({ sort:"agent", limit:6 }),
            window.reliqRegistryApi.discoverTop({ sort:"movement", limit:6 }),
            window.reliqRegistryApi.discoverTop({ sort:"newest", limit:6 }),
            window.reliqRegistryApi.discoverTop({ kind:"API", sort:"trust", limit:6 }),
            window.reliqRegistryApi.discoverTop({ kind:"PRODUCT", sort:"trust", limit:6 }),
          ]);
          if (!cancelled) setCats({
            featured: top.profiles, topTrusted: top.profiles, topAgentReady: agent.profiles,
            fastestImproving: moving.profiles, recentlyAdded: recent.profiles,
            topTrustedApis: apis.profiles, topTrustedProducts: products.profiles,
            topAgentReadySoftware: agent.profiles, fastestImprovingProfiles: moving.profiles,
          });
        }
      } catch (e) { if (!cancelled) setError(e); }
      finally { if (!cancelled) setLoading(false); }
    })();
    return () => { cancelled = true; };
  }, [stateKey, active, reloadKey]);

  const loadMore = async () => {
    if (!results.nextCursor) return;
    try {
      const r = await window.reliqRegistryApi.discover(buildDiscoverParams(state, { cursor: results.nextCursor }));
      setResults(prev => ({ items: [...prev.items, ...(r.profiles||[])], hasMore: !!r.hasMore, nextCursor: r.nextCursor||null, matched: prev.matched + (r.count ?? (r.profiles||[]).length) }));
    } catch (e) { setError(e); }
  };

  return (
    <LandingLayout go={go} pageTitle="Reliq Trust Registry">
      <div style={{maxWidth:920, margin:"40px auto 100px", padding:"0 20px"}}>
        <h1 style={{fontFamily:"var(--font-display)", fontSize:24, fontWeight:700, color:"var(--fg-0)", marginBottom:6}}>
          Discover trusted software
        </h1>
        <p style={{fontSize:13.5, color:"var(--fg-2)", marginBottom:8, lineHeight:1.6}}>
          Public, canonical trust profiles for companies, products, APIs, and websites.
        </p>
        <div style={{display:"flex", alignItems:"center", gap:8, marginBottom:22, padding:"8px 12px", borderRadius:8, background:"var(--teal-bg)", border:"1px solid rgba(0,212,170,0.2)"}}>
          <Icon name="sparkles" size={13} style={{color:"var(--teal)"}} />
          <span style={{fontSize:12, color:"var(--fg-1)", flex:1}}>Profiles in the Reliq Registry can be discovered by both humans and AI agents.</span>
          <button onClick={() => go("/trust-api")} style={{display:"inline-flex", alignItems:"center", gap:4, background:"none", border:"none", cursor:"pointer", fontSize:12, fontWeight:600, color:"var(--teal)", whiteSpace:"nowrap"}}>
            <Icon name="book" size={12} /> Trust API docs
          </button>
        </div>

        <DiscoveryControls state={state} set={set} onClear={clear} active={active} />

        {error ? (
          <LoadBox testid="error-state"><span style={{color:"var(--red)"}}>Couldn’t reach the registry API ({error.code || "error"}).</span> <button onClick={retry} style={{background:"none", border:"none", color:"var(--teal)", cursor:"pointer", fontSize:13}}>Retry</button></LoadBox>
        ) : loading ? (
          <LoadBox testid="loading">Loading the registry…</LoadBox>
        ) : active ? (
          <div data-testid="results">
            <div style={{display:"flex", alignItems:"baseline", justifyContent:"space-between", marginBottom:12}}>
              <h2 style={{fontFamily:"var(--font-display)", fontSize:16, fontWeight:700, color:"var(--fg-0)", margin:0}}>Results</h2>
              <span className="mono" style={{fontSize:11, color:"var(--fg-3)"}}>{results.matched} match{results.matched === 1 ? "" : "es"}</span>
            </div>
            {results.matched === 0 ? (
              <LoadBox testid="empty-state">No profiles match your filters. <button onClick={clear} style={{background:"none", border:"none", color:"var(--teal)", cursor:"pointer", fontSize:13, padding:0}}>Clear filters</button></LoadBox>
            ) : (
              <React.Fragment>
                <CardGrid profiles={results.items} go={go} />
                {results.hasMore && (
                  <div style={{textAlign:"center", marginTop:18}}>
                    <button className="btn btn-sm" onClick={loadMore}>Load more</button>
                  </div>
                )}
              </React.Fragment>
            )}
          </div>
        ) : cats ? (
          <div data-testid="categories">
            <CategorySection title="Featured profiles" subtitle="Hand-picked" profiles={cats.featured} go={go} />
            <CategorySection title="Top trusted profiles" subtitle="Highest Trust Score" profiles={cats.topTrusted} go={go} />
            <CategorySection title="Top agent-ready profiles" subtitle="Best Agent Readiness" profiles={cats.topAgentReady} go={go} />
            <CategorySection title="Fastest improving profiles" subtitle="Biggest 30-day gains" profiles={cats.fastestImproving} go={go} />
            <CategorySection title="Recently added profiles" subtitle="Newest to the registry" profiles={cats.recentlyAdded} go={go} />

            <div style={{borderTop:"1px solid var(--line-1)", margin:"8px 0 24px"}} />
            <h2 style={{fontFamily:"var(--font-display)", fontSize:18, fontWeight:700, color:"var(--fg-0)", marginBottom:18}}>Discovery categories</h2>
            <CategorySection title="Top Trusted APIs"          profiles={cats.topTrustedApis} go={go} />
            <CategorySection title="Top Trusted Products"      profiles={cats.topTrustedProducts} go={go} />
            <CategorySection title="Top Agent-Ready Software"  profiles={cats.topAgentReadySoftware} go={go} />
            <CategorySection title="Fastest Improving Profiles" profiles={cats.fastestImprovingProfiles} go={go} />
          </div>
        ) : null}
      </div>
    </LandingLayout>
  );
};

// ── SEO / OG / JSON-LD / agent metadata injection (backend-provided) ──
const clearProfileHead = () => {
  document.head.querySelectorAll("[data-reliq-seo]").forEach((el) => el.remove());
};

const applyProfileHead = (meta) => {
  clearProfileHead();
  const add = (tag, attrs, text) => {
    const el = document.createElement(tag);
    el.setAttribute("data-reliq-seo", "");
    Object.keys(attrs).forEach((k) => el.setAttribute(k, attrs[k]));
    if (text != null) el.textContent = text;
    document.head.appendChild(el);
  };
  document.title = meta.title;
  add("link", { rel: "canonical", href: meta.canonical });
  add("meta", { name: "description", content: meta.description });
  add("meta", { property: "og:title", content: meta.openGraph.title });
  add("meta", { property: "og:description", content: meta.openGraph.description });
  add("meta", { property: "og:image", content: meta.openGraph.image });
  add("meta", { property: "og:type", content: meta.openGraph.type });
  add("meta", { property: "og:url", content: meta.openGraph.url });
  add("meta", { name: "twitter:card", content: meta.twitter.card });
  add("meta", { name: "twitter:title", content: meta.twitter.title });
  add("meta", { name: "twitter:description", content: meta.twitter.description });
  add("meta", { name: "twitter:image", content: meta.twitter.image });
  add("script", { type: "application/ld+json" }, JSON.stringify(meta.jsonLd));
  add("script", { type: "application/json", id: "reliq-agent-metadata" }, JSON.stringify(meta.agent));
};

// ── Registry profile (canonical page) — backend-driven ───────────
const RegistryProfile = ({ go }) => {
  const slug = (window.location.hash.replace(/^#\/?/, "").split("?")[0].split("/")[1]) || "";
  const [p, setP] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    let cancelled = false;
    setLoading(true); setError(null); setP(null);
    window.reliqRegistryApi.getProfile(slug)
      .then((data) => {
        if (cancelled) return;
        setP(data);
        // Inject the backend-provided SEO / JSON-LD / agent metadata (no client recompute).
        if (data.seo) applyProfileHead({
          title: data.seo.title, canonical: data.seo.canonicalUrl, description: data.seo.description,
          openGraph: data.seo.openGraph, twitter: data.seo.twitter, jsonLd: data.jsonLd || {}, agent: data.agent || {},
        });
      })
      .catch((e) => { if (!cancelled) { setError(e); document.title = "Profile not found — Reliq"; } })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; clearProfileHead(); };
  }, [slug]);

  if (loading) {
    return (
      <LandingLayout go={go} pageTitle="Loading…">
        <div style={{maxWidth:700, margin:"60px auto", padding:"0 20px"}}><LoadBox testid="profile-loading">Loading trust profile…</LoadBox></div>
      </LandingLayout>
    );
  }

  if (error || !p) {
    const notFound = error && error.status === 404;
    return (
      <LandingLayout go={go} pageTitle={notFound ? "Profile not found" : "Registry error"}>
        <div data-testid="profile-error" style={{maxWidth:560, margin:"80px auto", padding:"0 20px", textAlign:"center"}}>
          <h1 style={{fontFamily:"var(--font-display)", fontSize:22, color:"var(--fg-0)"}}>{notFound ? "Profile not found" : "Couldn’t load this profile"}</h1>
          <p style={{color:"var(--fg-2)", marginTop:8}}>{notFound ? `No trust profile exists for “${slug}”.` : `The registry API returned an error (${error?.code || "error"}).`}</p>
          <button className="btn btn-sm" style={{marginTop:16}} onClick={() => go("/registry")}>Browse the registry</button>
        </div>
      </LandingLayout>
    );
  }

  const t = p.trust;
  const reportId = p.report && p.report.publicUrl ? p.report.publicUrl.split("/").pop() : null;
  return (
    <LandingLayout go={go} pageTitle={`${p.name} — Reliq Trust Profile`}>
      <div style={{maxWidth:700, margin:"40px auto 100px", padding:"0 20px"}}>
        {/* Header */}
        <div style={{display:"flex", alignItems:"flex-start", justifyContent:"space-between", gap:16, marginBottom:20}}>
          <div>
            <div style={{display:"flex", alignItems:"center", gap:8, marginBottom:4}}>
              <h1 style={{fontFamily:"var(--font-display)", fontSize:22, fontWeight:700, color:"var(--fg-0)", margin:0}}>{p.name}</h1>
              <span className="mono" style={{fontSize:10, color:"var(--fg-3)", border:"1px solid var(--line-2)", borderRadius:4, padding:"1px 6px"}}>{KIND_LABEL[p.kind] || p.kind}</span>
            </div>
            {p.description && <div style={{fontSize:12.5, color:"var(--fg-2)"}}>{p.description}</div>}
            <div className="mono" style={{fontSize:11, color:"var(--fg-3)", marginTop:6}}>
              {p.websiteUrl} · Last scan {p.lastScanDate ? p.lastScanDate.slice(0,10) : "—"}
            </div>
            <div className="mono" style={{fontSize:10.5, color:"var(--fg-3)", marginTop:3}}>reliq.dev/registry/{p.slug}</div>
          </div>
          <div style={{textAlign:"right", flexShrink:0}}>
            <div style={{fontFamily:"var(--font-display)", fontSize:34, fontWeight:700, color:scoreColor(t ? t.overall : 0), lineHeight:1}}>{t ? t.overall : "—"}</div>
            <div className="mono" style={{fontSize:11, color:"var(--fg-2)", marginTop:2}}>{t ? t.grade : "Not verified"}</div>
          </div>
        </div>

        {t && <TrustBadgePills badges={t.badges} />}

        {/* Pillars */}
        {t && (
          <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"16px 18px", margin:"18px 0"}}>
            <div style={{fontWeight:600, fontSize:13, color:"var(--fg-0)", marginBottom:12}}>Trust Score pillars</div>
            <div style={{display:"flex", flexDirection:"column", gap:10}}>
              {t.pillars.map(pl => (
                <div key={pl.key} style={{display:"flex", alignItems:"center", gap:12}}>
                  <div style={{fontFamily:"var(--font-mono)", fontSize:14, fontWeight:600, minWidth:36, textAlign:"right", color:scoreColor(pl.score)}}>{pl.score}</div>
                  <div style={{flex:1, fontSize:12.5, color:"var(--fg-1)"}}>{pl.label}</div>
                  <div className="mono" style={{fontSize:10.5, color:"var(--fg-3)"}}>{pl.grade}</div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Top actions */}
        {t && t.topActions && t.topActions.length > 0 && (
          <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"16px 18px", marginBottom:18}}>
            <div style={{fontWeight:600, fontSize:13, color:"var(--fg-0)", marginBottom:10}}>Top actions to improve score</div>
            <ol style={{margin:0, paddingLeft:18, display:"flex", flexDirection:"column", gap:6}}>
              {t.topActions.map((a, i) => <li key={i} style={{fontSize:12.5, color:"var(--fg-1)"}}>{a.title}</li>)}
            </ol>
          </div>
        )}

        {/* Trust history + score movement */}
        <TrustHistory trend={p.trend} history={(p.history || []).map(h => ({ capturedAt: (h.capturedAt||"").slice(0,10), overall: h.overallScore, grade: h.grade }))} />

        {/* Trust monitoring + recent changes */}
        <TrustMonitoring monitoring={p.monitoring} changes={p.recentChanges} />

        {/* Embeddable Trust Badges */}
        <TrustBadges slug={p.slug} badges={p.badgeEmbeds} />

        {/* Machine-readable + report links */}
        <div style={{display:"flex", gap:12, flexWrap:"wrap"}}>
          <button className="btn btn-sm" onClick={() => window.reliqToast?.info("Machine-readable JSON: " + p.jsonUrl)}>
            <Icon name="code" size={12} /> Machine-readable JSON
          </button>
          {reportId && (
            <button className="btn btn-sm btn-ghost" onClick={() => go("/r/" + reportId)}>
              <Icon name="file-text" size={12} /> View full report
            </button>
          )}
        </div>
      </div>
    </LandingLayout>
  );
};

// ── Registry publishing workflow (Increment 13) ──────────────────
const PUBLISH_BASE = { site: "https://reliq.dev", api: "https://api.reliq.dev" };
const slugifyName = (s) => window.publishSlugify(s);
const gradeFromScore = (s) => s >= 90 ? "Excellent" : s >= 75 ? "Good" : s >= 60 ? "Needs Work" : s >= 40 ? "Risky" : "Not Ready";

const CopyRow = ({ label, value }) => {
  const [copied, setCopied] = React.useState(false);
  const copy = () => { try { navigator.clipboard?.writeText(value); } catch (e) { /* noop */ } setCopied(true); window.reliqToast?.info("Copied"); setTimeout(() => setCopied(false), 1400); };
  return (
    <div style={{marginBottom:10}}>
      {label && <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:4}}>{label}</div>}
      <div style={{display:"flex", gap:8, alignItems:"center"}}>
        <div style={{flex:1, minWidth:0, padding:"7px 10px", background:"var(--bg-1)", border:"1px solid var(--line-2)", borderRadius:7}}>
          <span className="mono" style={{fontSize:11.5, color:"var(--fg-2)", overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap", display:"block"}}>{value}</span>
        </div>
        <button className="btn btn-sm" onClick={copy}>{copied ? "Copied" : "Copy"}</button>
      </div>
    </div>
  );
};

const RegistryPublishModal = ({ report, go, onClose }) => {
  const r = report || {};
  const [name, setName] = React.useState(r.app || r.name || "");
  const [kind, setKind] = React.useState("PRODUCT");
  const [slug, setSlug] = React.useState(slugifyName(r.app || r.name || ""));
  const [slugTouched, setSlugTouched] = React.useState(false);
  const [description, setDescription] = React.useState("");
  const [websiteUrl, setWebsiteUrl] = React.useState("");
  const [result, setResult] = React.useState(null);
  const [publishing, setPublishing] = React.useState(false);
  const [apiError, setApiError] = React.useState(null);

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    const prev = document.body.style.overflow; document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = prev; };
  }, [onClose]);

  // Keep slug auto-synced to the name until the user edits it manually.
  const onName = (v) => { setName(v); if (!slugTouched) setSlug(slugifyName(v)); };

  const score = r.score != null ? r.score : null;
  const previewTrust = score == null ? null : {
    overall: score, grade: gradeFromScore(score),
    badges: { trustReady: score >= 80, agentReady: score >= 75, integrationReady: score >= 70 },
  };

  // Light client-side UX validation only — the BACKEND is authoritative (uniqueness,
  // workspace ownership, entitlement). Server errors (409/422/403) are surfaced below.
  const error = !name.trim()
    ? "A profile name is required."
    : !/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/.test(slug)
      ? "Slug must be lowercase letters, numbers, and hyphens."
      : null;

  const publish = async () => {
    if (error || publishing) return;
    setPublishing(true); setApiError(null);
    try {
      const data = await window.reliqRegistryApi.publishProfile({
        name: name.trim(), kind, slug,
        description: description || undefined,
        websiteUrl: websiteUrl || undefined,
        reportPublicId: r.id || undefined,
      });
      setResult({ slug: data.slug, canonical: data.canonicalUrl, jsonUrl: data.jsonUrl, badges: data.badgeEmbeds || [] });
      window.reliqToast?.success("Published to the Reliq Registry");
    } catch (e) {
      setApiError(e);
    } finally {
      setPublishing(false);
    }
  };

  return (
    <div onClick={onClose} role="dialog" aria-modal="true" aria-label="Publish to Registry" style={{
      position:"fixed", inset:0, zIndex:9000, background:"rgba(0,0,0,0.62)",
      backdropFilter:"blur(6px)", WebkitBackdropFilter:"blur(6px)",
      display:"flex", alignItems:"flex-start", justifyContent:"center", padding:"40px 20px", overflowY:"auto",
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        background:"var(--bg-1)", border:"1px solid var(--line-2)", borderRadius:16,
        width:"100%", maxWidth:640, boxShadow:"0 40px 100px rgba(0,0,0,0.5)", overflow:"hidden",
      }}>
        <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", padding:"16px 18px", borderBottom:"1px solid var(--line-1)"}}>
          <h2 style={{fontFamily:"var(--font-display)", fontSize:15, fontWeight:700, margin:0, color:"var(--fg-0)"}}>
            {result ? "Published to Registry" : "Publish to Registry"}
          </h2>
          <button className="btn btn-sm btn-ghost" onClick={onClose} aria-label="Close"><Icon name="x" size={14} /></button>
        </div>

        <div style={{padding:"18px"}}>
          {!result ? (
            <React.Fragment>
              <div style={{display:"flex", gap:18, flexWrap:"wrap"}}>
                {/* Form */}
                <div data-testid="publish-form" style={{flex:"1 1 300px", minWidth:0, display:"flex", flexDirection:"column", gap:12}}>
                  <label style={{display:"block"}}>
                    <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:4}}>Profile name</div>
                    <input value={name} onChange={(e) => onName(e.target.value)} style={{width:"100%", boxSizing:"border-box", padding:"8px 10px", borderRadius:7, border:"1px solid var(--line-2)", background:"var(--bg-1)", color:"var(--fg-0)", fontSize:13}} />
                  </label>
                  <label style={{display:"block"}}>
                    <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:4}}>Kind</div>
                    <select value={kind} onChange={(e) => setKind(e.target.value)} style={{...selStyle, width:"100%"}}>
                      <option value="COMPANY">Company</option>
                      <option value="PRODUCT">Product</option>
                      <option value="API">API</option>
                      <option value="WEBSITE">Website</option>
                    </select>
                  </label>
                  <label style={{display:"block"}}>
                    <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:4}}>Slug</div>
                    <input value={slug} onChange={(e) => { setSlug(e.target.value); setSlugTouched(true); }} style={{width:"100%", boxSizing:"border-box", padding:"8px 10px", borderRadius:7, border:"1px solid var(--line-2)", background:"var(--bg-1)", color:"var(--fg-0)", fontSize:13, fontFamily:"var(--font-mono)"}} />
                    <div className="mono" style={{fontSize:10.5, color:"var(--fg-3)", marginTop:3}}>reliq.dev/registry/{slug || "…"}</div>
                  </label>
                  <label style={{display:"block"}}>
                    <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:4}}>Description</div>
                    <textarea value={description} onChange={(e) => setDescription(e.target.value)} rows={2} style={{width:"100%", boxSizing:"border-box", padding:"8px 10px", borderRadius:7, border:"1px solid var(--line-2)", background:"var(--bg-1)", color:"var(--fg-0)", fontSize:13, resize:"vertical"}} />
                  </label>
                  <label style={{display:"block"}}>
                    <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:4}}>Website URL</div>
                    <input value={websiteUrl} onChange={(e) => setWebsiteUrl(e.target.value)} placeholder="https://example.com" style={{width:"100%", boxSizing:"border-box", padding:"8px 10px", borderRadius:7, border:"1px solid var(--line-2)", background:"var(--bg-1)", color:"var(--fg-0)", fontSize:13}} />
                  </label>
                </div>

                {/* Preview */}
                <div data-testid="publish-preview" style={{flex:"1 1 200px", minWidth:0}}>
                  <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", marginBottom:8}}>Preview</div>
                  <div style={{background:"var(--bg-2)", border:"1px solid var(--line-1)", borderRadius:10, padding:"14px"}}>
                    <div style={{fontWeight:600, fontSize:14, color:"var(--fg-0)"}}>{name || "Untitled"}</div>
                    <div className="mono" style={{fontSize:10.5, color:"var(--fg-3)", marginBottom:8}}>{KIND_LABEL[kind]}</div>
                    {previewTrust ? (
                      <React.Fragment>
                        <div style={{display:"flex", alignItems:"baseline", gap:8}}>
                          <span style={{fontFamily:"var(--font-display)", fontSize:30, fontWeight:700, color:scoreColor(previewTrust.overall), lineHeight:1}}>{previewTrust.overall}</span>
                          <span className="mono" style={{fontSize:11, color:"var(--fg-2)"}}>{previewTrust.grade}</span>
                        </div>
                        <TrustBadgePills badges={previewTrust.badges} />
                      </React.Fragment>
                    ) : (
                      <div style={{fontSize:12, color:"var(--fg-3)"}}>No Trust Score available for this report.</div>
                    )}
                  </div>
                </div>
              </div>

              {(error || apiError) && <div data-testid="publish-error" style={{marginTop:12, fontSize:12, color:"var(--red)"}}>{error || apiError.message}</div>}

              <div style={{display:"flex", justifyContent:"flex-end", gap:8, marginTop:16}}>
                <button className="btn btn-sm btn-ghost" onClick={onClose}>Cancel</button>
                <button className="btn btn-sm" disabled={!!error || publishing} onClick={publish} style={(error || publishing) ? {opacity:0.5, cursor:"not-allowed"} : {}}>
                  <Icon name="check" size={12} /> {publishing ? "Publishing…" : "Publish"}
                </button>
              </div>
            </React.Fragment>
          ) : (
            <div data-testid="publish-success">
              <div style={{display:"flex", alignItems:"center", gap:8, marginBottom:14, color:"var(--teal)"}}>
                <Icon name="check-circle" size={16} />
                <span style={{fontSize:13, fontWeight:600}}>{name} is live in the Reliq Registry.</span>
              </div>
              <CopyRow label="Canonical profile URL" value={result.canonical} />
              <CopyRow label="Public JSON URL" value={result.jsonUrl} />
              <div className="mono" style={{fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em", color:"var(--fg-3)", margin:"14px 0 8px"}}>Badge embeds</div>
              {result.badges.map((b) => (
                <div key={b.type} style={{display:"flex", alignItems:"center", gap:8, marginBottom:8, flexWrap:"wrap"}}>
                  <span style={{flex:"1 1 160px", fontSize:12, color:"var(--fg-1)"}}>{b.label}</span>
                  <button className="btn btn-sm btn-ghost" onClick={() => { try { navigator.clipboard?.writeText(b.html); } catch (e) {} window.reliqToast?.info("Copied HTML"); }}>Copy HTML</button>
                  <button className="btn btn-sm btn-ghost" onClick={() => { try { navigator.clipboard?.writeText(b.markdown); } catch (e) {} window.reliqToast?.info("Copied Markdown"); }}>Copy Markdown</button>
                </div>
              ))}
              <div style={{display:"flex", justifyContent:"flex-end", gap:8, marginTop:18}}>
                <button className="btn btn-sm btn-ghost" onClick={() => go && go("/registry/" + result.slug)}>View profile</button>
                <button className="btn btn-sm" onClick={onClose}>Done</button>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { RegistryIndex, RegistryProfile, RegistryPublishModal });
