const summaryEl = document.getElementById("catalogSummary");
const charactersEl = document.getElementById("charactersCatalog");
const stagesEl = document.getElementById("stagesCatalog");
const mechanicsEl = document.getElementById("mechanicsCatalog");
const searchInput = document.getElementById("searchInput");

let catalog = null;

const escapeHtml = (value) =>
  String(value ?? "")
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;");

const mediaHtml = (asset) => {
  if (asset.mime_type?.startsWith("image/")) {
    return `<img src="${asset.file_url}" alt="${escapeHtml(asset.label || asset.slot)}" />`;
  }
  if (asset.mime_type?.startsWith("audio/")) {
    return `<audio controls src="${asset.file_url}"></audio>`;
  }
  if (asset.mime_type?.startsWith("video/")) {
    return `<video controls src="${asset.file_url}"></video>`;
  }
  return `<a class="small-button" href="${asset.file_url}" target="_blank" rel="noreferrer">Open File</a>`;
};

async function loadCatalog() {
  const response = await fetch("/api/public/catalog");
  const payload = await response.json();
  catalog = payload;
  render();
}

function matchesSearch(row, query) {
  if (!query) {
    return true;
  }
  const haystack = JSON.stringify(row).toLowerCase();
  return haystack.includes(query);
}

function assetsFor(entityType, slug) {
  return (catalog.assets || []).filter((asset) => asset.entity_type === entityType && asset.entity_slug === slug);
}

function renderSummary(query) {
  const counts = [
    ["Visible Characters", (catalog.characters || []).filter((row) => matchesSearch(row, query)).length],
    ["Visible Stages", (catalog.stages || []).filter((row) => matchesSearch(row, query)).length],
    ["Public Mechanics", (catalog.mechanics || []).filter((row) => matchesSearch(row, query)).length],
    ["Approved Assets", (catalog.assets || []).filter((row) => matchesSearch(row, query)).length],
  ];
  summaryEl.innerHTML = counts
    .map(
      ([label, value]) => `
        <article class="stat-card">
          <span class="stat-label">${escapeHtml(label)}</span>
          <span class="stat-value">${escapeHtml(value)}</span>
        </article>
      `
    )
    .join("");
}

function renderCards(rows, entityType) {
  if (!rows.length) {
    return `<div class="empty-state">No visible entries match the current filter.</div>`;
  }

  return `
    <div class="catalog-grid">
      ${rows
        .map((row) => {
          const assets = assetsFor(entityType, row.slug);
          return `
            <article class="catalog-card">
              <div class="catalog-title">
                <div>
                  <h3>${escapeHtml(row.display_name)}</h3>
                  <div class="catalog-meta">${escapeHtml(row.slug)}</div>
                </div>
                <div class="pill-row">
                  ${row.status ? `<span class="pill">${escapeHtml(row.status)}</span>` : ""}
                  ${row.category ? `<span class="pill">${escapeHtml(row.category)}</span>` : ""}
                  ${row.legal_status ? `<span class="pill">${escapeHtml(row.legal_status)}</span>` : ""}
                </div>
              </div>
              <p class="muted-copy">${escapeHtml(row.description || row.summary || "No public summary yet.")}</p>
              <div class="pill-row">
                ${
                  String(row.tags || "")
                    .split(",")
                    .map((tag) => tag.trim())
                    .filter(Boolean)
                    .map((tag) => `<span class="pill">${escapeHtml(tag)}</span>`)
                    .join("")
                }
              </div>
              ${
                assets.length
                  ? `
                    <div class="catalog-media">
                      ${assets.map((asset) => mediaHtml(asset)).join("")}
                    </div>
                  `
                  : ""
              }
            </article>
          `;
        })
        .join("")}
    </div>
  `;
}

function renderMechanics(rows) {
  if (!rows.length) {
    return `<div class="empty-state">No mechanics match the current filter.</div>`;
  }

  return `
    <div class="catalog-grid">
      ${rows
        .map(
          (row) => `
            <article class="catalog-card">
              <div class="catalog-title">
                <div>
                  <h3>${escapeHtml(row.display_name)}</h3>
                  <div class="catalog-meta">${escapeHtml(row.subsystem)}</div>
                </div>
                ${row.tuning_value ? `<span class="pill">${escapeHtml(row.tuning_value)}</span>` : ""}
              </div>
              <p class="muted-copy">${escapeHtml(row.summary || "No public summary yet.")}</p>
              ${
                row.target_file
                  ? `<div class="catalog-meta">Target: ${escapeHtml(row.target_file)}</div>`
                  : ""
              }
            </article>
          `
        )
        .join("")}
    </div>
  `;
}

function render() {
  const query = searchInput.value.trim().toLowerCase();
  const characters = (catalog.characters || []).filter((row) => matchesSearch(row, query));
  const stages = (catalog.stages || []).filter((row) => matchesSearch(row, query));
  const mechanics = (catalog.mechanics || []).filter((row) => matchesSearch(row, query));

  renderSummary(query);
  charactersEl.innerHTML = `<div class="table-card"><div class="section-header"><div><h2>Characters</h2><p class="section-copy">Public roster entries and approved art.</p></div></div>${renderCards(characters, "character")}</div>`;
  stagesEl.innerHTML = `<div class="table-card"><div class="section-header"><div><h2>Stages</h2><p class="section-copy">Public stage sheets and approved previews.</p></div></div>${renderCards(stages, "stage")}</div>`;
  mechanicsEl.innerHTML = `<div class="table-card"><div class="section-header"><div><h2>Mechanics</h2><p class="section-copy">Visible system notes and tuning references.</p></div></div>${renderMechanics(mechanics)}</div>`;
}

searchInput.addEventListener("input", () => {
  if (catalog) {
    render();
  }
});

loadCatalog();
