const fallbackIcon = "/assets/argus-icon.png?v=argus-panoptes-3d-20260508";
const appIcons = new Map([
  ["aletheia-kotlin", "/assets/aletheia-icon.svg?v=aletheia-launcher-20260508"]
]);

const state = {
  apps: [],
  selectedSlug: null
};

const catalogGrid = document.getElementById("catalog-grid");
const recentReleases = document.getElementById("recent-releases");
const appIcon = document.getElementById("app-icon");
const appName = document.getElementById("app-name");
const appDescription = document.getElementById("app-description");
const releaseVersion = document.getElementById("release-version");
const detailMeta = document.getElementById("detail-meta");
const releaseList = document.getElementById("release-list");
const manifestLink = document.getElementById("manifest-link");
const primaryDownload = document.getElementById("primary-download");
const refreshButton = document.getElementById("refresh-button");

refreshButton.addEventListener("click", () => loadAll());
window.addEventListener("hashchange", handleHashChange);

loadAll();

async function loadAll() {
  await Promise.all([loadCatalog(), loadRecentReleases()]);
  handleHashChange();
}

async function loadCatalog() {
  const response = await fetch("/api/apps");
  const apps = await response.json();
  state.apps = Array.isArray(apps) ? apps : [];
  renderCatalog();
}

async function loadRecentReleases() {
  const response = await fetch("/api/releases/recent");
  const items = await response.json();

  if (!Array.isArray(items) || !items.length) {
    recentReleases.innerHTML = '<div class="empty-state">Пока нет опубликованных релизов.</div>';
    return;
  }

  recentReleases.innerHTML = items.map(item => `
    <article class="timeline-item">
      <header>
        <h3>${escapeHtml(item.appName)}</h3>
        <span class="pill">${escapeHtml(item.release.version)}</span>
      </header>
      <p>${escapeHtml(item.release.platform)} - ${escapeHtml(item.release.packageKind)} - ${formatDate(item.release.publishedAt)}</p>
      <div class="release-links">
        <a href="#${encodeURIComponent(item.slug)}">Открыть карточку</a>
        <a href="${item.release.downloadPath}">Скачать</a>
      </div>
    </article>
  `).join("");
}

function renderCatalog() {
  if (!state.apps.length) {
    catalogGrid.innerHTML = '<div class="empty-state">Пока нет опубликованных приложений.</div>';
    renderEmptyDetail();
    return;
  }

  catalogGrid.innerHTML = state.apps.map(app => {
    const isActive = app.slug === state.selectedSlug;
    const latest = app.latestRelease;
    return `
      <article class="app-card ${isActive ? "active" : ""}" data-slug="${escapeHtml(app.slug)}">
        ${renderAppIcon("app-card-icon", app, 72)}
        <div>
          <h3>${escapeHtml(app.name)}</h3>
          <p>${escapeHtml(app.summary)}</p>
          <div class="rating-line">
            <span>${latest ? escapeHtml(latest.version) : "нет релиза"}</span>
            <span>${latest ? escapeHtml(latest.packageKind) : "пакет"}</span>
            <span>${app.releaseCount} версия</span>
          </div>
        </div>
      </article>
    `;
  }).join("");

  for (const card of catalogGrid.querySelectorAll(".app-card")) {
    card.addEventListener("click", () => {
      window.location.hash = card.dataset.slug;
    });
  }
}

function handleHashChange() {
  const slugFromHash = decodeURIComponent(window.location.hash.replace(/^#/, ""));
  const hashApp = state.apps.find(app => app.slug === slugFromHash);
  const nextSlug = hashApp?.slug ?? state.apps[0]?.slug ?? null;
  state.selectedSlug = nextSlug;

  if (!nextSlug) {
    renderEmptyDetail();
    return;
  }

  renderCatalog();

  if (slugFromHash && !hashApp) {
    window.history.replaceState(null, "", `#${encodeURIComponent(nextSlug)}`);
  }

  loadAppDetail(nextSlug);
}

async function loadAppDetail(slug) {
  const response = await fetch(`/api/apps/${encodeURIComponent(slug)}`);
  if (!response.ok) {
    renderEmptyDetail("Карточка приложения не загрузилась.");
    return;
  }

  const app = await response.json();
  const latest = app.releases[0] ?? null;
  appIcon.src = getAppIconSrc(app);
  appName.textContent = app.name;
  appDescription.textContent = app.description || app.summary;
  manifestLink.href = `/api/apps/${encodeURIComponent(app.slug)}/manifest`;

  if (latest) {
    releaseVersion.textContent = latest.version;
    primaryDownload.href = latest.downloadPath;
    primaryDownload.removeAttribute("aria-disabled");
  } else {
    releaseVersion.textContent = "-";
    primaryDownload.href = "#";
    primaryDownload.setAttribute("aria-disabled", "true");
  }

  detailMeta.innerHTML = `
    ${renderMetaBlock("Обновлено", formatDate(app.updatedAt))}
    ${renderMetaBlock("Платформа", latest ? latest.platform : "Не опубликовано")}
    ${renderMetaBlock("Тип", latest ? latest.packageKind : "-")}
    ${renderMetaBlock("Размер", latest ? formatBytes(latest.packageSizeBytes) : "-")}
  `;

  if (!app.releases.length) {
    releaseList.innerHTML = '<div class="empty-state">Для этого приложения ещё нет опубликованного файла.</div>';
    return;
  }

  releaseList.innerHTML = app.releases.slice(0, 1).map(release => `
    <article class="release-item">
      <header>
        <h3>Файл ${escapeHtml(release.version)}</h3>
        <span class="pill">${escapeHtml(release.channel)}</span>
      </header>
      <p>${formatDate(release.publishedAt)} - ${formatBytes(release.packageSizeBytes)} - ${escapeHtml(release.originalFileName)}</p>
      ${release.notes ? `<p class="release-notes">${escapeHtml(release.notes)}</p>` : ""}
      <div class="pill-row">
        <span class="pill">${escapeHtml(release.platform)}</span>
        <span class="pill">${escapeHtml(release.packageKind)}</span>
      </div>
      <div class="release-links">
        <a href="${release.downloadPath}">Скачать файл</a>
        <a href="/api/apps/${encodeURIComponent(app.slug)}/manifest?platform=${encodeURIComponent(release.platform)}&channel=${encodeURIComponent(release.channel)}" target="_blank" rel="noreferrer">Открыть manifest</a>
      </div>
    </article>
  `).join("");
}

function renderEmptyDetail(message = "Данные приложения появятся после загрузки API.") {
  appIcon.src = fallbackIcon;
  appName.textContent = "Argus";
  appDescription.textContent = message;
  releaseVersion.textContent = "-";
  detailMeta.innerHTML = "";
  releaseList.innerHTML = "";
  manifestLink.href = "#";
  primaryDownload.href = "#";
  primaryDownload.setAttribute("aria-disabled", "true");
}

function renderMetaBlock(label, value) {
  return `
    <div class="meta-block">
      <span class="meta-label">${escapeHtml(label)}</span>
      <div class="meta-value">${escapeHtml(value)}</div>
    </div>
  `;
}

function renderAppIcon(className, app, size) {
  return `<img class="${escapeHtml(className)}" src="${escapeHtml(getAppIconSrc(app))}" alt="" width="${size}" height="${size}">`;
}

function getAppIconSrc(app) {
  return appIcons.get(app?.slug) ?? fallbackIcon;
}

function formatDate(value) {
  return new Intl.DateTimeFormat("ru-RU", {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit"
  }).format(new Date(value));
}

function formatBytes(bytes) {
  if (!Number.isFinite(bytes) || bytes <= 0) {
    return "0 Б";
  }

  const units = ["Б", "КБ", "МБ", "ГБ"];
  let index = 0;
  let value = bytes;

  while (value >= 1024 && index < units.length - 1) {
    value /= 1024;
    index += 1;
  }

  return `${value.toFixed(value >= 10 || index === 0 ? 0 : 1)} ${units[index]}`;
}

function escapeHtml(value) {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}
