/* Screens part 1: Dashboard, Catalog Entries (list + detail), Works, Pieces */
const D1 = window.OO_DATA;

function Dashboard({ setRoute }) {
  const totals = {
    entries: D1.ENTRIES.length,
    published: D1.ENTRIES.filter(e => e.isPublished).length,
    needsMatch: D1.ENTRIES.filter(e => !e.isEditorialMatch).length,
    locales: 11,
  };
  return (
    <div>
      <PageHeader
        eyebrow="Panoramica"
        title="Buongiorno, Antonio"
        subtitle="Stato del catalogo Opera One — 8 maggio 2026"
        actions={<>
          <button className="btn"><Icon name="download" />Report editoriale</button>
          <button className="btn opera"><Icon name="plus" />Nuovo entry</button>
        </>}
      />
      <div className="stats">
        <div className="stat"><div className="lbl">Catalog entries</div><div className="val">{totals.entries.toLocaleString("it-IT")}</div><div className="delta">+18 ultima settimana</div></div>
        <div className="stat"><div className="lbl">Pubblicati su CDN</div><div className="val">{totals.published}</div><div className="delta">{Math.round(totals.published/totals.entries*100)}% del totale</div></div>
        <div className="stat"><div className="lbl">Da matchare</div><div className="val">{totals.needsMatch}</div><div className="delta down">richiede review editoriale</div></div>
        <div className="stat"><div className="lbl">Lingue supportate</div><div className="val">{totals.locales}</div><div className="delta">copertura media 47%</div></div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 18, marginTop: 18 }}>
        <div className="card">
          <div className="card-head between" style={{ justifyContent: "space-between" }}>
            <div><h3>Lavoro editoriale aperto</h3><div className="sub">12 task assegnati al tuo team</div></div>
            <button className="btn ghost sm">Vedi tutto <Icon name="arrowRight" /></button>
          </div>
          <table className="table">
            <thead><tr><th>Task</th><th>Tipo</th><th>Assegnato</th><th>Avanzamento</th></tr></thead>
            <tbody>
              {[
                { t: "Tradurre 14 sinossi in EN/DE", k: "translate", who: "Sara F.", p: 0.62 },
                { t: "Rivedere match Mozart Nozze (4 entries)", k: "match", who: "Antonio V.", p: 0.25 },
                { t: "Bio Maria Callas — completare ko/ja/zh", k: "bio", who: "Maya R.", p: 0.78 },
                { t: "Pubblicare 23 asset CDN — Cantolopera Q2", k: "publish", who: "Luca B.", p: 0.42 },
                { t: "Difficulty 1–10 per Lieder Romantik", k: "edit", who: "Maya R.", p: 0.10 },
              ].map((r, i) => (
                <tr key={i} onClick={() => setRoute({ page: "entries" })}>
                  <td><div style={{ fontWeight: 500 }}>{r.t}</div></td>
                  <td><span className="pill gray">{r.k}</span></td>
                  <td className="muted">{r.who}</td>
                  <td style={{ width: 200 }}>
                    <div className="progress"><span style={{ width: (r.p*100) + "%" }}></span></div>
                    <div className="mono" style={{ marginTop: 3, fontSize: 10.5, color: "var(--ink-3)" }}>{Math.round(r.p*100)}%</div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        <div className="card">
          <div className="card-head"><div><h3>Attività recente</h3><div className="sub">Ultimi cambi sul catalogo</div></div></div>
          <div className="card-body" style={{ padding: 0 }}>
            {D1.ACTIVITY.map((a, i) => (
              <div key={i} style={{ padding: "12px 18px", borderBottom: i === D1.ACTIVITY.length-1 ? "none" : "1px solid var(--rule)", display: "flex", gap: 10, alignItems: "flex-start" }}>
                <div style={{ width: 24, height: 24, borderRadius: 99, background: "var(--paper-3)", display: "flex", alignItems: "center", justifyContent: "center", flex: "none", fontFamily: "var(--serif)", fontSize: 11 }}>
                  {a.who.split(" ").map(s => s[0]).join("").slice(0,2)}
                </div>
                <div style={{ fontSize: 12.5, lineHeight: 1.4 }}>
                  <strong>{a.who}</strong> <span className="muted">{a.action}</span> <strong>{a.target}</strong>
                  <div className="muted mono" style={{ fontSize: 10.5, marginTop: 2 }}>{a.time}</div>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 18, marginTop: 18 }}>
        {D1.CATALOGS.slice(0,3).map(c => (
          <div className="card" key={c.id} style={{ cursor: "pointer" }} onClick={() => setRoute({ page: "catalogs", id: c.id })}>
            <div className="card-body">
              <div className="row between" style={{ justifyContent: "space-between" }}>
                <div className="eyebrow" style={{ fontSize: 10.5, textTransform: "uppercase", letterSpacing: ".15em", color: "var(--opera)" }}>{c.provider}</div>
                <StatusPill status={c.status} />
              </div>
              <h3 style={{ fontFamily: "var(--serif)", fontSize: 20, margin: "8px 0" }}>{c.name}</h3>
              <p className="muted" style={{ fontSize: 12, margin: 0 }}>{c.description}</p>
              <div className="divider"></div>
              <div className="row" style={{ justifyContent: "space-between", fontSize: 11.5 }}>
                <span className="muted">{c.entries.toLocaleString("it-IT")} entries</span>
                <span className="mono muted">{c.delivery.cdnBaseUrl.replace("https://","").slice(0,28)}…</span>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ── Catalog Entries ─────────────────────────────────── */
function EntriesList({ setRoute }) {
  const [filters, setFilters] = useState({ catalog: null, status: null, completeness: null, q: "" });
  const [sel, setSel] = useState(new Set());
  const [tab, setTab] = useState("all");

  const filtered = D1.ENTRIES.filter(e => {
    if (tab === "to-match" && e.isEditorialMatch) return false;
    if (tab === "review" && e.status !== "review") return false;
    if (tab === "draft" && e.status !== "draft") return false;
    if (tab === "published" && !e.isPublished) return false;
    if (filters.catalog && e.catalogId !== filters.catalog) return false;
    if (filters.status && e.status !== filters.status) return false;
    if (filters.completeness && e.completenessStatus !== filters.completeness) return false;
    if (filters.q && !(e.title || "").toLowerCase().includes(filters.q.toLowerCase())) return false;
    return true;
  });

  const toggleSel = (id) => {
    const s = new Set(sel);
    if (s.has(id)) s.delete(id); else s.add(id);
    setSel(s);
  };
  const allSel = filtered.length > 0 && filtered.every(e => sel.has(e.id));
  const someSel = sel.size > 0 && !allSel;
  const toggleAll = () => {
    if (allSel) setSel(new Set());
    else setSel(new Set(filtered.map(e => e.id)));
  };

  return (
    <div>
      <PageHeader
        eyebrow="Catalogo · Lista principale"
        title="Catalog Entries"
        subtitle="L'unità editoriale principale del catalogo. Ogni riga collega una sorgente di import a un work, un piece e i suoi asset."
        actions={<>
          <button className="btn"><Icon name="download" />Esporta</button>
          <button className="btn"><Icon name="upload" />Import</button>
          <button className="btn opera"><Icon name="plus" />Nuovo entry</button>
        </>}
      />

      <div className="tabs" style={{ marginBottom: 14 }}>
        <div className={"tab " + (tab === "all" ? "active" : "")} onClick={() => setTab("all")}>Tutti<span className="count">{D1.ENTRIES.length}</span></div>
        <div className={"tab " + (tab === "to-match" ? "active" : "")} onClick={() => setTab("to-match")}>Da matchare<span className="count">{D1.ENTRIES.filter(e=>!e.isEditorialMatch).length}</span></div>
        <div className={"tab " + (tab === "review" ? "active" : "")} onClick={() => setTab("review")}>In review<span className="count">{D1.ENTRIES.filter(e=>e.status==="review").length}</span></div>
        <div className={"tab " + (tab === "draft" ? "active" : "")} onClick={() => setTab("draft")}>Draft<span className="count">{D1.ENTRIES.filter(e=>e.status==="draft").length}</span></div>
        <div className={"tab " + (tab === "published" ? "active" : "")} onClick={() => setTab("published")}>Pubblicati<span className="count">{D1.ENTRIES.filter(e=>e.isPublished).length}</span></div>
      </div>

      <div className="filterbar" style={{ marginBottom: 12 }}>
        <Icon name="filter" /> <span className="muted" style={{ fontSize: 12 }}>Filtra:</span>
        <span className={"chip " + (filters.catalog ? "active" : "")} onClick={() => setFilters({...filters, catalog: filters.catalog ? null : "cat_1"})}>
          Catalog · {filters.catalog ? D1.catalogById(filters.catalog).name : "Tutti"} <Icon name="chevronDown" />
        </span>
        <span className={"chip " + (filters.status ? "active" : "")} onClick={() => setFilters({...filters, status: filters.status ? null : "ready"})}>Status · {filters.status || "Tutti"} <Icon name="chevronDown" /></span>
        <span className="chip">Completeness · Tutti <Icon name="chevronDown" /></span>
        <span className="chip">Voce <Icon name="chevronDown" /></span>
        <span className="chip">Lingua sorgente <Icon name="chevronDown" /></span>
        <span className="chip">Compositore <Icon name="chevronDown" /></span>
        <span style={{ marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }}>
          <span className="muted" style={{ fontSize: 11.5 }}>{filtered.length} di {D1.ENTRIES.length}</span>
          <button className="btn sm ghost"><Icon name="columns" /> Colonne</button>
          <button className="btn sm ghost"><Icon name="sort" /> Ordina</button>
        </span>
      </div>

      {sel.size > 0 && (
        <div className="bulkbar">
          <span style={{ fontWeight: 500 }}>{sel.size} selezionati</span>
          <button className="btn sm"><Icon name="check" />Marca ready</button>
          <button className="btn sm"><Icon name="publish" />Pubblica su CDN</button>
          <button className="btn sm"><Icon name="globe" />Genera traduzioni</button>
          <button className="btn sm"><Icon name="raccolta" />Aggiungi a raccolta</button>
          <span style={{ marginLeft: "auto" }}></span>
          <button className="btn sm danger"><Icon name="trash" />Elimina</button>
          <button className="btn sm" onClick={() => setSel(new Set())}><Icon name="x" /></button>
        </div>
      )}

      <div className="card" style={{ overflow: "hidden" }}>
        <table className="table">
          <thead>
            <tr>
              <th style={{ width: 30 }}><span className={"cb " + (allSel ? "on" : (someSel ? "indet" : ""))} onClick={toggleAll}></span></th>
              <th style={{ width: 280 }}>Titolo</th>
              <th>Work</th>
              <th>Compositore</th>
              <th>Voce</th>
              <th style={{ width: 60 }}>Diff.</th>
              <th>Locales</th>
              <th>Asset</th>
              <th>Versione</th>
              <th>Status</th>
              <th style={{ width: 80 }}></th>
            </tr>
          </thead>
          <tbody>
            {filtered.slice(0, 22).map(e => (
              <tr key={e.id} className={sel.has(e.id) ? "selected" : ""} onClick={() => setRoute({ page: "entries", id: e.id })}>
                <td onClick={(ev) => { ev.stopPropagation(); toggleSel(e.id); }}>
                  <span className={"cb " + (sel.has(e.id) ? "on" : "")}></span>
                </td>
                <td>
                  <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
                    <div className="cover" style={{ background: e.workId ? `linear-gradient(135deg, oklch(0.6 0.05 ${(parseInt(e.id.replace(/\D/g,"")||"0",10)*47)%360}), oklch(0.35 0.06 ${(parseInt(e.id.replace(/\D/g,"")||"0",10)*47)%360 + 30}))` : "var(--paper-3)" }}></div>
                    <div style={{ minWidth: 0 }}>
                      <div style={{ fontFamily: "var(--serif)", fontSize: 13, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: 240 }}>{e.title}</div>
                      <div className="mono muted" style={{ fontSize: 10.5 }}>{e.sourceItemId}</div>
                    </div>
                  </div>
                </td>
                <td>{e.workTitle ? <span style={{ fontFamily: "var(--serif)" }}>{e.workTitle}</span> : <span className="muted" style={{ fontSize: 11 }}>— da matchare</span>}</td>
                <td className="muted">{e.composerId ? D1.contribById(e.composerId).name.split(" ").slice(-1)[0] : "—"}</td>
                <td>{e.vocalParts.map(v => <span className="pill gray" style={{ marginRight: 4 }} key={v}>{D1.vocalPartById(v)?.name || v}</span>)}</td>
                <td>{e.difficulty ? <span className="mono">{e.difficulty}/10</span> : <span className="muted">—</span>}</td>
                <td>
                  <div style={{ display: "inline-flex", gap: 2 }}>
                    {Array.from({ length: 11 }).map((_, i) => (
                      <span key={i} style={{ display: "inline-block", width: 6, height: 8, borderRadius: 1, background: i < e.localeCoverage ? "var(--opera)" : "var(--paper-3)" }}></span>
                    ))}
                  </div>
                  <div className="muted mono" style={{ fontSize: 10, marginTop: 2 }}>{e.localeCoverage}/11</div>
                </td>
                <td>
                  <span style={{ display: "inline-flex", gap: 4 }}>
                    {e.assets.includes("audio.mp3.ins") && <span className="pill gray" title="Instrumental">INS</span>}
                    {e.assets.includes("audio.mp3.voc") && <span className="pill gray" title="Vocal">VOC</span>}
                    {e.assets.some(a => a.startsWith("score.pdf")) && <span className="pill gray" title="Partitura">PDF</span>}
                  </span>
                </td>
                <td className="muted" style={{ fontSize: 11.5 }}>{e.version}</td>
                <td><StatusPill status={e.status} />{e.isPublished && <span className="pill green dot" style={{ marginLeft: 4 }}></span>}</td>
                <td><button className="btn sm ghost"><Icon name="more" /></button></td>
              </tr>
            ))}
          </tbody>
        </table>
        <div style={{ padding: "10px 14px", display: "flex", alignItems: "center", borderTop: "1px solid var(--rule)", fontSize: 11.5, color: "var(--ink-3)" }}>
          <span>Mostrate 22 di {filtered.length}</span>
          <span style={{ marginLeft: "auto", display: "flex", gap: 6 }}>
            <button className="btn sm ghost">‹</button>
            <span className="mono" style={{ alignSelf: "center" }}>1 / {Math.ceil(filtered.length/22)}</span>
            <button className="btn sm ghost">›</button>
          </span>
        </div>
      </div>
    </div>
  );
}

function EntryDetail({ id, setRoute }) {
  const e = D1.ENTRIES.find(x => x.id === id);
  if (!e) return <div className="empty"><h3>Entry non trovato</h3></div>;
  const w = e.workId ? D1.workById(e.workId) : null;
  const p = e.pieceId ? D1.pieceById(e.pieceId) : null;
  const composer = e.composerId ? D1.contribById(e.composerId) : null;
  const cat = D1.catalogById(e.catalogId);
  const assets = D1.ASSETS.filter(a => a.catalogEntryId === e.id);
  const [tab, setTab] = useState("overview");

  return (
    <div>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
        <button className="btn ghost sm" onClick={() => setRoute({ page: "entries" })}>‹ Lista</button>
        <span className="muted mono" style={{ fontSize: 11 }}>{e.sourceItemId} · {e.catalogCode} · {e.barcode}</span>
        <span style={{ marginLeft: "auto" }}></span>
        <button className="btn sm"><Icon name="copy" /> Duplica</button>
        <button className="btn sm"><Icon name="open" /> Apri in CDN</button>
        <button className="btn sm opera"><Icon name="publish" /> Pubblica</button>
      </div>

      <div className="page-h">
        <div className="cover xl" style={{ background: w ? `linear-gradient(135deg, oklch(0.6 0.07 ${(p?.id?.length||4)*40}), oklch(0.32 0.08 ${(p?.id?.length||4)*40+30}))` : "var(--paper-3)" }}>
          <div className="lbl">{cat.provider}</div>
        </div>
        <div className="titles" style={{ marginBottom: 4 }}>
          <div className="eyebrow">{w ? w.title : "— senza match editoriale"}{p ? ` · ${p.pieceType}${p.act ? ` · atto ${p.act}` : ""}` : ""}</div>
          <h1 style={{ fontSize: 32 }}>{e.title}</h1>
          <p>{composer ? composer.name : "Compositore —"}{e.performers && e.performers.length > 0 ? ` · ${e.performers.map(id => D1.contribById(id)?.name).filter(Boolean).join(", ")}` : ""}</p>
          <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
            <StatusPill status={e.status} />
            {e.isPublished && <span className="pill green">Pubblicato su CDN</span>}
            {!e.isEditorialMatch && <span className="pill warn">Match editoriale mancante</span>}
            <span className="pill gray">{e.completenessStatus.replace(/_/g, " ").toLowerCase()}</span>
            <span className="pill opera">{e.version}</span>
          </div>
        </div>
        <div className="actions" style={{ alignItems: "flex-start" }}>
          <div className="player" style={{ minWidth: 320 }}>
            <div className="play"><Icon name="play" size={12} /></div>
            <div className="track-info">
              <span className="t-title">Audio · INS</span>
              <span className="t-sub">{D1.fmtDuration(e.duration)} · mp3</span>
            </div>
            <div className="seek"><i style={{ width: "32%" }}></i></div>
            <span className="time">1:42 / {D1.fmtDuration(e.duration)}</span>
          </div>
        </div>
      </div>

      <div className="tabs" style={{ marginBottom: 18 }}>
        {[
          ["overview", "Panoramica"],
          ["editorial", "Editoriale & traduzioni"],
          ["assets", "Asset & CDN", assets.length],
          ["credits", "Crediti", e.performers.length],
          ["history", "Cronologia"],
          ["raw", "Riga sorgente"],
        ].map(([k, l, c]) => (
          <div key={k} className={"tab " + (tab === k ? "active" : "")} onClick={() => setTab(k)}>{l}{c != null && <span className="count">{c}</span>}</div>
        ))}
      </div>

      {tab === "overview" && (
        <div className="detail wide-aside">
          <div className="col">
            <div className="card"><div className="card-head"><h3>Identità editoriale</h3></div>
              <div className="card-body">
                <dl className="kv">
                  <dt>Catalog</dt><dd><a onClick={() => setRoute({ page: "catalogs", id: cat.id })} style={{ cursor: "pointer", textDecoration: "underline dotted" }}>{cat.name}</a> <span className="muted mono">{cat.slug}</span></dd>
                  <dt>Editorial type</dt><dd>{e.editorialType || <span className="muted">—</span>}</dd>
                  <dt>Work</dt><dd>{w ? <a onClick={() => setRoute({ page: "works", id: w.id })} style={{ cursor: "pointer", textDecoration: "underline dotted", fontFamily: "var(--serif)" }}>{w.title}</a> : <span className="muted">— nessun match</span>}</dd>
                  <dt>Piece</dt><dd>{p ? <span style={{ fontFamily: "var(--serif)" }}>{p.title}</span> : <span className="muted">—</span>}</dd>
                  <dt>Piece type</dt><dd>{p?.pieceType || <span className="muted">—</span>}</dd>
                  <dt>Atto · Scena</dt><dd>{p?.act ? `Atto ${p.act}${p.scene ? `, scena ${p.scene}` : ""}` : <span className="muted">—</span>}</dd>
                  <dt>Lingua del brano</dt><dd>{e.language ? <span className="flag-cell"><span style={{ fontWeight: 600 }}>{e.language.toUpperCase()}</span> · inferita editorialmente</span> : <span className="muted">—</span>}</dd>
                  <dt>Difficoltà</dt><dd>{e.difficulty ? `${e.difficulty}/10` : <span className="muted">—</span>}</dd>
                  <dt>Note editoriali</dt><dd>{e.notes ? <em>{e.notes}</em> : <span className="muted">Nessuna nota</span>}</dd>
                </dl>
              </div>
            </div>

            <div className="card"><div className="card-head"><h3>Voce & ruoli</h3><span className="sub">vocal_parts e characters della piece collegata</span></div>
              <div className="card-body">
                <div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
                  {(p?.vocalParts || []).map(vp => {
                    const v = D1.vocalPartById(vp); if (!v) return null;
                    return <div key={vp} style={{ padding: "10px 14px", border: "1px solid var(--rule)", borderRadius: 6, background: "#fff" }}>
                      <div className="eyebrow" style={{ color: "var(--gold)" }}>Vocal part</div>
                      <div style={{ fontFamily: "var(--serif)", fontSize: 18 }}>{v.name}</div>
                    </div>;
                  })}
                  {(p?.characters || []).map(ch => {
                    const c = D1.characterById(ch); if (!c) return null;
                    return <div key={ch} style={{ padding: "10px 14px", border: "1px solid var(--rule)", borderRadius: 6, background: "#fff" }}>
                      <div className="eyebrow" style={{ color: "var(--opera)" }}>Character</div>
                      <div style={{ fontFamily: "var(--serif)", fontSize: 18 }}>{c.name}</div>
                      <div className="muted" style={{ fontSize: 11 }}>{c.work}</div>
                    </div>;
                  })}
                  {(!p?.vocalParts?.length && !p?.characters?.length) && <span className="muted">Nessun ruolo collegato</span>}
                </div>
              </div>
            </div>

            <div className="card"><div className="card-head"><h3>Asset collegati</h3><span className="sub">{assets.length} asset · pubblicati: {assets.filter(a => a.isPublished).length}</span></div>
              <table className="table">
                <thead><tr><th>Filename</th><th>Type</th><th>Variant</th><th>Format</th><th>Size</th><th>Storage</th><th>Status</th><th></th></tr></thead>
                <tbody>
                  {assets.map(a => (
                    <tr key={a.id}>
                      <td><span className="mono">{a.filename}</span>{a.isPrimary && <span className="pill opera" style={{ marginLeft: 6 }}>primary</span>}</td>
                      <td className="muted">{a.assetType}</td>
                      <td><span className="pill gray">{a.variant}</span></td>
                      <td className="mono">{a.format}</td>
                      <td className="mono muted">{D1.fmtBytes(a.sizeBytes)}</td>
                      <td className="muted" style={{ fontSize: 11 }}>{a.cdnUrl ? "CDN · pubblico" : "S3 · privato"}</td>
                      <td>{a.isPublished ? <span className="pill green">Pubblicato</span> : <span className="pill gray">Ready</span>}</td>
                      <td><div className="row"><button className="btn sm ghost"><Icon name="play" size={12}/></button><button className="btn sm ghost"><Icon name="download"/></button></div></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          <aside className="col">
            <div className="card"><div className="card-body">
              <div className="eyebrow" style={{ marginBottom: 6 }}>Stato pubblicazione</div>
              <div className="row" style={{ justifyContent: "space-between" }}>
                <div>
                  <div style={{ fontFamily: "var(--serif)", fontSize: 22 }}>{e.isPublished ? "Pubblicato" : "Non pubblicato"}</div>
                  <div className="muted" style={{ fontSize: 11 }}>resolverPolicy · oo_cantolopera_cdn_main</div>
                </div>
                <div className={"toggle " + (e.isPublished ? "on" : "")}></div>
              </div>
              <div className="divider"></div>
              <div className="eyebrow" style={{ marginBottom: 6 }}>Copertura traduzioni</div>
              <div className="progress"><span style={{ width: (e.localeCoverage/11*100) + "%" }}></span></div>
              <div className="row" style={{ marginTop: 6, fontSize: 11, color: "var(--ink-3)" }}>
                <span>{e.localeCoverage} su 11 lingue</span>
                <span style={{ marginLeft: "auto", color: "var(--opera)", cursor: "pointer", fontWeight: 500 }}>Apri editor →</span>
              </div>
            </div></div>

            <div className="card"><div className="card-head"><h3>Performer credits</h3></div>
              <div className="card-body">
                {e.performers.length === 0 && <span className="muted">Nessun performer collegato.</span>}
                {e.performers.map(pid => {
                  const cc = D1.contribById(pid); if (!cc) return null;
                  return <div key={pid} className="row" style={{ padding: "8px 0", borderBottom: "1px solid var(--rule)", gap: 10 }}>
                    <div style={{ width: 32, height: 32, borderRadius: 99, background: "linear-gradient(135deg, var(--gold), var(--opera))", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--serif)" }}>
                      {cc.name.split(" ").map(n=>n[0]).slice(0,2).join("")}
                    </div>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontFamily: "var(--serif)", fontSize: 13 }}>{cc.name}</div>
                      <div className="muted" style={{ fontSize: 11 }}>{cc.types.join(", ")}{cc.vocalProfile ? ` · ${cc.vocalProfile}` : ""}</div>
                    </div>
                    <span className="pill gray">{cc.types[0] === "conductor" ? "conductor" : "primary_performer"}</span>
                  </div>;
                })}
                <button className="btn sm ghost" style={{ marginTop: 8 }}><Icon name="plus" /> Aggiungi credito</button>
              </div>
            </div>

            <div className="card"><div className="card-head"><h3>Modifiche</h3></div>
              <div className="card-body" style={{ fontSize: 12 }}>
                <div className="muted">Ultimo aggiornamento</div>
                <div><strong>{e.updatedBy}</strong> · {e.updatedAt}</div>
                <div className="divider"></div>
                <div className="muted">Creato da import</div>
                <div className="mono" style={{ fontSize: 11 }}>ib_1 · Cantolopera-Catalog-2026-04.xlsx</div>
              </div>
            </div>
          </aside>
        </div>
      )}

      {tab === "editorial" && <EditorialTab entry={e} piece={p} work={w} />}
      {tab === "assets" && <AssetsTab assets={assets} entry={e} />}
      {tab === "credits" && <CreditsTab entry={e} />}
      {tab === "history" && <HistoryTab entry={e} />}
      {tab === "raw" && <RawTab entry={e} />}
    </div>
  );
}

function EditorialTab({ entry, piece, work }) {
  const [src, setSrc] = useState("it");
  const fields = piece ? [
    { key: "title", label: "Titolo", values: piece.locTitle, placeholder: "Da tradurre…" },
    { key: "pieceType", label: "Piece type", values: { it: piece.pieceType || "", en: piece.pieceType }, placeholder: "es. aria, lied, brindisi" },
    { key: "synopsis", label: "Sinossi", values: { it: piece.id === "p_caro" ? "Gilda, sola in giardino, sussurra il nome che il giovane le ha appena rivelato." : "" }, multiline: true, placeholder: "Sinossi editoriale del brano…" },
    { key: "description", label: "Descrizione", values: {}, multiline: true, placeholder: "Note descrittive editoriali (contesto, ascolto)…" },
  ] : [];

  return (
    <div className="detail wide-aside">
      <div className="col">
        <div className="card">
          <div className="card-head" style={{ display: "flex", alignItems: "center" }}>
            <h3>Lavoro editoriale multilingua</h3>
            <span style={{ marginLeft: "auto", display: "flex", gap: 6, alignItems: "center" }}>
              <span className="muted" style={{ fontSize: 11 }}>Lingua sorgente</span>
              <select className="input" style={{ width: 130 }} value={src} onChange={(ev)=>setSrc(ev.target.value)}>
                {D1.LOCALES.map(l => <option key={l.code} value={l.code}>{l.flag} · {l.label}</option>)}
              </select>
              <button className="btn sm"><Icon name="globe" /> Genera AI</button>
            </span>
          </div>
          <div className="card-body" style={{ padding: 0 }}>
            {fields.map(f => (
              <div key={f.key} style={{ borderBottom: "1px solid var(--rule)" }}>
                <div style={{ padding: "12px 18px 6px", display: "flex", alignItems: "baseline", gap: 10 }}>
                  <div className="eyebrow" style={{ minWidth: 110 }}>{f.label}</div>
                  <span className="muted" style={{ fontSize: 11 }}>fields.localized{f.key.charAt(0).toUpperCase()+f.key.slice(1)} · {Object.keys(f.values).length} di 11 lingue</span>
                </div>
                <div className="locale-grid" style={{ margin: "0 14px 14px", gridTemplateColumns: "56px 1fr 90px" }}>
                  <div className="h">Lingua</div><div className="h">Valore</div><div className="h">Stato</div>
                  {D1.LOCALES.map(l => {
                    const v = f.values[l.code]; const isSrc = l.code === src;
                    return <React.Fragment key={l.code}>
                      <div className="c flag">{l.flag}{isSrc && <span style={{ color: "var(--opera)", marginLeft: 4 }}>•</span>}</div>
                      <div className="c" style={{ background: isSrc ? "var(--paper-2)" : "#fff" }}>
                        {v ? <span style={{ fontFamily: f.key === "title" ? "var(--serif)" : undefined, fontSize: 13 }}>{v}</span>
                           : <span className="muted" style={{ fontStyle: "italic" }}>{f.placeholder}</span>}
                      </div>
                      <div className="c" style={{ textAlign: "right" }}>
                        {v ? (isSrc ? <span className="pill ink">sorgente</span> : <span className="pill green">tradotto</span>) : <span className="pill gray">vuoto</span>}
                      </div>
                    </React.Fragment>;
                  })}
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <aside className="col">
        <div className="card"><div className="card-body">
          <div className="eyebrow">Regola editoriale</div>
          <p style={{ fontSize: 12.5, marginTop: 4 }}>L'import non è meccanico: titoli, descrizioni, sinossi, difficoltà e traduzioni richiedono lavoro editoriale.</p>
          <div className="divider"></div>
          <div className="eyebrow">Piece type</div>
          <div style={{ display: "flex", gap: 4, marginTop: 4 }}>
            <span className="pill opera">{piece?.pieceType || "—"}</span>
            <span className="muted" style={{ fontSize: 11 }}>diverso da works.operaType / vocalType</span>
          </div>
          <div className="divider"></div>
          <div className="eyebrow">Difficulty</div>
          <div className="row" style={{ marginTop: 6, gap: 2 }}>
            {Array.from({ length: 10 }).map((_, i) => (
              <span key={i} style={{ flex: 1, height: 8, background: i < (piece?.difficulty || 0) ? "var(--opera)" : "var(--paper-3)", borderRadius: 1 }}></span>
            ))}
          </div>
          <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>Scala 1–10, valutata editorialmente</div>
        </div></div>
      </aside>
    </div>
  );
}

function AssetsTab({ assets, entry }) {
  return <div className="card" style={{ overflow: "hidden" }}>
    <table className="table">
      <thead><tr><th>Filename</th><th>Type · Variant</th><th>objectKey</th><th>cdnUrl</th><th>Size · Hash</th><th>Status</th><th></th></tr></thead>
      <tbody>
        {assets.map(a => (
          <tr key={a.id}>
            <td><span className="mono">{a.filename}</span></td>
            <td><span className="pill gray">{a.assetType}</span> <span className="pill opera">{a.variant}</span></td>
            <td><span className="mono muted" style={{ fontSize: 10.5 }}>{a.objectKey}</span></td>
            <td>{a.cdnUrl ? <span className="mono" style={{ color: "var(--green)", fontSize: 10.5 }}>{a.cdnUrl.replace("https://","").slice(0,60)}…</span> : <span className="muted">— non pubblicato</span>}</td>
            <td><div className="mono" style={{ fontSize: 10.5 }}>{D1.fmtBytes(a.sizeBytes)}</div><div className="mono muted" style={{ fontSize: 10 }}>{a.checksum.slice(0, 22)}</div></td>
            <td>{a.isPublished ? <span className="pill green">Published</span> : <span className="pill gray">Ready</span>}</td>
            <td><button className="btn sm">{a.isPublished ? "Depubblica" : "Pubblica"}</button></td>
          </tr>
        ))}
      </tbody>
    </table>
  </div>;
}

function CreditsTab({ entry }) {
  return <div className="card" style={{ padding: 18 }}>
    <h3 style={{ marginTop: 0, fontFamily: "var(--serif)" }}>Performer credits</h3>
    <p className="muted" style={{ fontSize: 12 }}>I performer reali (cantanti, direttori, orchestre) collegati a questo entry. Il <span className="mono">creditType</span> appartiene al contesto dell'entry, non all'identità del contributor.</p>
    {entry.performers.map(pid => {
      const c = D1.contribById(pid); if (!c) return null;
      return <div key={pid} className="row" style={{ padding: "12px 0", borderBottom: "1px solid var(--rule)", gap: 14 }}>
        <div style={{ width: 40, height: 40, borderRadius: 99, background: "linear-gradient(135deg, var(--gold), var(--opera))", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--serif)", fontSize: 14 }}>
          {c.name.split(" ").map(n=>n[0]).slice(0,2).join("")}
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: "var(--serif)", fontSize: 16 }}>{c.name}</div>
          <div className="muted" style={{ fontSize: 11 }}>{c.types.join(", ")}{c.vocalProfile ? ` · ${c.vocalProfile}` : ""} · {c.nationality}</div>
        </div>
        <select className="input" style={{ width: 200 }} defaultValue={c.types[0] === "conductor" ? "conductor" : "primary_performer"}>
          <option>primary_performer</option><option>conductor</option><option>orchestra</option><option>choir</option>
        </select>
        <button className="btn sm ghost"><Icon name="trash" /></button>
      </div>;
    })}
    <button className="btn" style={{ marginTop: 12 }}><Icon name="plus" /> Aggiungi performer</button>
  </div>;
}

function HistoryTab({ entry }) {
  const events = [
    { t: entry.updatedAt, who: entry.updatedBy, what: "ha aggiornato la sinossi (it, en)", k: "edit" },
    { t: "3 giorni fa", who: "Sara Ferri", what: "ha pubblicato l'asset INS su CDN", k: "publish" },
    { t: "1 settimana fa", who: "Antonio Vecchio", what: "ha collegato il performer Luciano Pavarotti", k: "link" },
    { t: "1 settimana fa", who: "Antonio Vecchio", what: "ha matchato l'entry con Rigoletto / Caro nome", k: "match" },
    { t: "2 settimane fa", who: "Sistema", what: "ha importato la riga sorgente (ib_1)", k: "import" },
  ];
  return <div className="card" style={{ padding: 0 }}>
    {events.map((ev, i) => <div key={i} style={{ padding: "14px 18px", display: "flex", gap: 14, borderBottom: i === events.length-1 ? "none" : "1px solid var(--rule)" }}>
      <div className="mono muted" style={{ width: 100, fontSize: 11 }}>{ev.t}</div>
      <div style={{ flex: 1, fontSize: 13 }}><strong>{ev.who}</strong> {ev.what}</div>
      <span className="pill gray">{ev.k}</span>
    </div>)}
  </div>;
}

function RawTab({ entry }) {
  return <div className="card" style={{ padding: 18, background: "#1B1612", color: "#E9DFC9" }}>
    <div className="eyebrow" style={{ color: "#998363" }}>Riga sorgente · catalog_import_rows</div>
    <pre style={{ margin: "10px 0 0", fontFamily: "var(--mono)", fontSize: 12, lineHeight: 1.6, color: "#E9DFC9" }}>{`{
  "_id": "${entry.id}",
  "catalogSlug": "${D1.catalogById(entry.catalogId).slug}",
  "sourceItemId": "${entry.sourceItemId}",
  "rowHash": "0xfa7c9b2e…",
  "parsingStatus": "ok",
  "normalizationStatus": "${entry.isEditorialMatch ? 'matched' : 'needs_match'}",
  "rowRaw": {
    "code": "${entry.catalogCode}",
    "barcode": "${entry.barcode}",
    "title": "${entry.title}",
    "version": "${entry.version}",
    "label": "${entry.label}",
    "duration_ms": ${entry.duration},
    "files": ${JSON.stringify(entry.assets, null, 4).split("\n").join("\n    ")}
  }
}`}</pre>
  </div>;
}

window.Dashboard = Dashboard;
window.EntriesList = EntriesList;
window.EntryDetail = EntryDetail;
