"use strict";

const gvlSnapshotEmpty = document.getElementById("gvl-snapshot-empty");
const gvlSnapshotContent = document.getElementById("gvl-snapshot-content");
const gvlSnapshotList = document.getElementById("gvl-snapshot-list");
const gvlSnapshotSummary = document.getElementById("gvl-snapshot-summary");
const gvlTechnicalFields = document.getElementById("gvl-technical-fields");
const gvlDebugData = document.getElementById("gvl-debug-data");
const gvlFetchOfficialButton = document.getElementById(
  "gvl-fetch-official-button"
);
const gvlFetchStatus = document.getElementById("gvl-fetch-status");
const gvlRebuildNormalizedButton = document.getElementById(
  "gvl-rebuild-normalized-button"
);
const gvlRebuildNormalizedStatus = document.getElementById(
  "gvl-rebuild-normalized-status"
);
const gvlVendorOverviewEmpty = document.getElementById(
  "gvl-vendor-overview-empty"
);
const gvlVendorOverviewDetails = document.getElementById(
  "gvl-vendor-overview-details"
);
const gvlVendorOverviewSummary = document.getElementById(
  "gvl-vendor-overview-summary"
);
const gvlVendorOverviewContent = document.getElementById(
  "gvl-vendor-overview-content"
);
const gvlVendorOverviewList = document.getElementById(
  "gvl-vendor-overview-list"
);
const gvlVendorDetailForm = document.getElementById("gvl-vendor-detail-form");
const gvlVendorIdInput = document.getElementById("gvl-vendor-id-input");
const gvlVendorDetailButton = document.getElementById(
  "gvl-vendor-detail-button"
);
const gvlVendorDetailStatus = document.getElementById(
  "gvl-vendor-detail-status"
);
const gvlVendorDetailResult = document.getElementById(
  "gvl-vendor-detail-result"
);

let gvlSnapshots = [];
let selectedSnapshotSha256 = null;
let selectedSnapshotSummary = null;
let selectedSnapshotVendors = [];

document.addEventListener("DOMContentLoaded", async () => {
  gvlFetchOfficialButton.addEventListener("click", async () => {
    await fetchOfficialGvl();
  });

  gvlRebuildNormalizedButton.addEventListener("click", async () => {
    await rebuildSelectedGvlSnapshotNormalizedData();
  });

  gvlVendorDetailForm.addEventListener("submit", async (event) => {
    event.preventDefault();
    await renderGvlVendorDetail();
  });

  await renderGvlSnapshots();
});

async function fetchOfficialGvl() {
  gvlFetchOfficialButton.disabled = true;
  renderFetchStatus("GVL wird aus Web geladen...");

  try {
    const result = await browser.runtime.sendMessage({
      type: "fetch_official_gvl"
    });

    if (!result?.success) {
      throw new Error(result?.error ?? "official_gvl_fetch_failed");
    }

    renderFetchStatus(buildGvlSyncStatusMessage(result));

    await renderGvlSnapshots();
    await renderSelectedGvlSnapshotSummary();
  } catch (error) {
    renderFetchStatus("GVL aus Web konnte nicht geladen werden.");
    console.warn("VG-Observe manual official GVL fetch failed", error);
  } finally {
    gvlFetchOfficialButton.disabled = false;
  }
}

function buildGvlSyncStatusMessage(result) {
  if (result?.syncStatus === "new_gvl_revision_stored_and_normalized") {
    return "GVL aus Web geladen, neue Revision gespeichert und normalisiert.";
  }

  if (result?.syncStatus === "known_gvl_rebuilt_from_local_evidence") {
    return "GVL aus Web geprüft; bekannte Revision aus lokaler Evidence neu aufgebaut.";
  }

  if (result?.syncStatus === "current_and_locally_available") {
    return "GVL aus Web geprüft; aktuelle Revision ist lokal vollständig verfügbar.";
  }

  return result?.alreadyKnown
    ? "GVL aus Web geprüft; Revision ist lokal verfügbar."
    : "GVL aus Web geladen.";
}

function renderFetchStatus(message) {
  gvlFetchStatus.textContent = message;
}

function renderRebuildStatus(message) {
  gvlRebuildNormalizedStatus.textContent = message;
}

async function rebuildSelectedGvlSnapshotNormalizedData() {
  const snapshot = findGvlSnapshot(selectedSnapshotSha256);

  if (!snapshot) {
    renderRebuildStatus("Keine Vendorliste ausgewählt.");
    return;
  }

  gvlRebuildNormalizedButton.disabled = true;
  renderRebuildStatus("Lokale Evidence wird neu normalisiert...");

  try {
    const result = await browser.runtime.sendMessage({
      type: "rebuild_gvl_snapshot_normalized_data",
      payload: {
        sha256: snapshot.sha256
      }
    });

    if (!result?.success) {
      throw new Error(
        result?.error ?? "rebuild_gvl_snapshot_normalized_data_failed"
      );
    }

    await renderSelectedGvlSnapshotSummary();
    renderRebuildStatus(buildRebuildSuccessMessage(result));

    if (gvlVendorIdInput.value) {
      await renderGvlVendorDetail();
    }
  } catch (error) {
    renderRebuildStatus("Lokaler Neuaufbau fehlgeschlagen.");
    console.warn("VG-Observe GVL normalized rebuild failed", error);
  } finally {
    gvlRebuildNormalizedButton.disabled =
      !doesSnapshotNeedNormalizedRebuild(selectedSnapshotSummary);
  }
}

function buildRebuildSuccessMessage(result) {
  const counts = result.counts ?? {};

  return [
    "Lokale GVL-Daten neu aufgebaut.",
    `Vendoren: ${formatCount(counts.vendorCount)}`,
    `Beziehungen: ${formatCount(counts.vendorRelationshipCount)}`
  ].join(" ");
}

async function renderGvlVendorDetail() {
  const vendorId = Number(gvlVendorIdInput.value);

  clearGvlVendorDetail();

  if (!Number.isInteger(vendorId) || vendorId <= 0) {
    renderGvlVendorDetailStatus("Bitte eine gültige Vendor-ID eingeben.");
    return;
  }

  gvlVendorDetailButton.disabled = true;
  renderGvlVendorDetailStatus("Vendor wird geladen...");

  try {
    const result = await browser.runtime.sendMessage({
      type: "get_gvl_vendor_detail",
      payload: {
        vendorId
      }
    });

    if (!result?.success) {
      throw new Error(result?.error ?? "get_gvl_vendor_detail_failed");
    }

    renderGvlVendorDetailStatus("Vendor geladen.");
    renderGvlVendorDetailResult(result.vendorDetail ?? {});
  } catch (error) {
    renderGvlVendorDetailStatus("Vendor konnte nicht geladen werden.");
    console.warn("VG-Observe GVL vendor detail failed", error);
  } finally {
    gvlVendorDetailButton.disabled = false;
  }
}

function clearGvlVendorDetail() {
  gvlVendorDetailResult.textContent = "";
}

function renderGvlVendorDetailStatus(message) {
  gvlVendorDetailStatus.textContent = message;
}

function renderGvlVendorDetailResult(detail) {
  const vendor = detail.vendor ?? {};
  const snapshot = detail.snapshot ?? {};
  const rawEvidence = detail.rawEvidence ?? {};

  gvlVendorDetailResult.textContent = "";
  gvlVendorDetailResult.append(
    buildKeyValueSection("Normalisierte Vendor-Felder", [
      ["Vendor-ID", formatNullable(vendor.vendorId)],
      ["Name", formatNullable(vendor.name)],
      ["Policy URL", formatNullable(vendor.policyUrl)],
      ["Deleted Date", formatNullable(vendor.deletedDate)],
      ["Uses Cookies", formatNullable(vendor.usesCookies)],
      ["Cookie Max Age Seconds", formatNullable(vendor.cookieMaxAgeSeconds)],
      ["Uses Non-Cookie Access", formatNullable(vendor.usesNonCookieAccess)],
      [
        "Device Storage Disclosure URL",
        formatNullable(vendor.deviceStorageDisclosureUrl)
      ],
      ["Domains", formatJsonValue(vendor.domains)],
      ["Snapshot SHA256", formatNullable(vendor.snapshotSha256)]
    ]),
    buildKeyValueSection("Snapshot-Herkunft", [
      ["Snapshot SHA256", formatNullable(snapshot.snapshotSha256)],
      ["Raw-GVL SHA256", formatNullable(snapshot.rawGvlSha256)],
      ["Vendorlisten-Version", formatNullable(snapshot.vendorListVersion)],
      ["TCF Policy Version", formatNullable(snapshot.tcfPolicyVersion)],
      ["Abrufzeitpunkt", formatNullable(snapshot.fetchedAt)],
      ["Snapshot erstellt", formatNullable(snapshot.createdAt)]
    ]),
    buildKeyValueSection("Raw-GVL-Evidence", [
      ["Raw-GVL SHA256", formatNullable(rawEvidence.rawGvlSha256)],
      ["Quelle", formatNullable(rawEvidence.sourceUrl)],
      ["Abrufzeitpunkt", formatNullable(rawEvidence.fetchedAt)],
      ["HTTP Status", formatNullable(rawEvidence.httpStatus)],
      ["Content-Type", formatNullable(rawEvidence.contentType)],
      ["Raw Body vorhanden", formatNullable(rawEvidence.hasRawBody)]
    ]),
    buildJsonDetails("Vollständiger rawVendor-Datensatz", vendor.rawVendor),
    buildJsonDetails("Vollständiger gvl_vendors-Datensatz", vendor)
  );
}

function buildKeyValueSection(title, rows) {
  const section = document.createElement("section");
  const heading = document.createElement("h3");
  const table = document.createElement("table");
  const body = document.createElement("tbody");

  section.className = "vendor-detail-section";
  heading.textContent = title;
  table.className = "summary-table";

  for (const [label, value] of rows) {
    const row = document.createElement("tr");
    const labelCell = document.createElement("th");
    const valueCell = document.createElement("td");

    labelCell.scope = "row";
    labelCell.textContent = label;
    valueCell.textContent = value;
    row.append(labelCell, valueCell);
    body.append(row);
  }

  table.append(body);
  section.append(heading, table);

  return section;
}

function buildJsonDetails(title, value) {
  const details = document.createElement("details");
  const summary = document.createElement("summary");
  const valuePre = document.createElement("pre");

  details.className = "technical-details";
  summary.textContent = title;
  valuePre.textContent = JSON.stringify(value ?? null, null, 2);
  details.append(summary, valuePre);

  return details;
}

async function renderGvlSnapshots() {
  try {
    const result = await browser.runtime.sendMessage({
      type: "list_gvl_snapshots"
    });

    if (!result?.success) {
      throw new Error(result?.error ?? "list_gvl_snapshots_failed");
    }

    gvlSnapshots = result.gvlSnapshots ?? [];

    if (gvlSnapshots.length === 0) {
      renderNoGvlSnapshots();
      return;
    }

    gvlSnapshotEmpty.hidden = true;
    gvlSnapshotContent.hidden = false;

    if (!findGvlSnapshot(selectedSnapshotSha256)) {
      selectedSnapshotSha256 = gvlSnapshots[0]?.sha256 ?? null;
    }

    renderGvlSnapshotList();
    await renderSelectedGvlSnapshotSummary();
  } catch (error) {
    gvlSnapshotEmpty.hidden = false;
    gvlSnapshotContent.hidden = true;
    gvlSnapshotEmpty.textContent =
      "Gespeicherte Vendorlisten konnten nicht geladen werden.";
    console.warn("VG-Observe GVL snapshot list failed", error);
  }
}

function renderNoGvlSnapshots() {
  gvlSnapshotList.textContent = "";
  clearGvlSnapshotSummary();
  clearGvlVendorOverview();
  gvlSnapshotEmpty.hidden = false;
  gvlSnapshotContent.hidden = true;
  gvlSnapshotEmpty.textContent =
    "Keine gespeicherten offiziellen Vendorlisten vorhanden.";
}

function renderGvlSnapshotList() {
  gvlSnapshotList.textContent = "";

  for (const snapshot of gvlSnapshots) {
    const row = document.createElement("tr");
    const isSelected = snapshot?.sha256 === selectedSnapshotSha256;

    row.className = isSelected ? "is-selected" : "";
    row.tabIndex = 0;
    row.setAttribute("role", "button");
    row.setAttribute("aria-pressed", isSelected ? "true" : "false");

    row.addEventListener("click", async () => {
      await selectGvlSnapshot(snapshot?.sha256 ?? null);
    });

    row.addEventListener("keydown", async (event) => {
      if (event.key === "Enter" || event.key === " ") {
        event.preventDefault();
        await selectGvlSnapshot(snapshot?.sha256 ?? null);
      }
    });

    appendListCell(row, formatNullable(snapshot?.vendorListVersion), "numeric");
    appendListCell(row, formatNullable(snapshot?.fetchedAt));
    appendListCell(row, shortenSha256(snapshot?.sha256), "sha-cell");
    appendListCell(row, formatNullable(snapshot?.sourceUrl), "url-cell");

    gvlSnapshotList.append(row);
  }
}

function appendListCell(row, value, className) {
  const cell = document.createElement("td");

  if (className) {
    cell.className = className;
  }

  cell.textContent = value;
  row.append(cell);
}

async function selectGvlSnapshot(sha256) {
  selectedSnapshotSha256 = sha256;
  renderGvlSnapshotList();
  renderRebuildStatus("");
  await renderSelectedGvlSnapshotSummary();
}

async function renderSelectedGvlSnapshotSummary() {
  const snapshot = findGvlSnapshot(selectedSnapshotSha256);

  clearGvlSnapshotSummary();
  clearGvlVendorOverview();

  if (!snapshot) {
    updateRebuildActionState(null);
    return;
  }

  try {
    const result = await browser.runtime.sendMessage({
      type: "get_gvl_snapshot_summary",
      payload: {
        sha256: snapshot.sha256
      }
    });

    if (!result?.success) {
      throw new Error(result?.error ?? "get_gvl_snapshot_summary_failed");
    }

    selectedSnapshotSummary = result.summary ?? {};
    renderSummaryTable(selectedSnapshotSummary);
    updateRebuildActionState(selectedSnapshotSummary);
    await renderVendorOverviewForSelectedSnapshot();
  } catch (error) {
    selectedSnapshotSummary = null;
    updateRebuildActionState(null);
    gvlSnapshotSummary.textContent =
      "Zusammenfassung dieser Vendorliste konnte nicht geladen werden.";
    console.warn("VG-Observe GVL snapshot summary failed", error);
  }
}

async function renderVendorOverviewForSelectedSnapshot() {
  const snapshot = findGvlSnapshot(selectedSnapshotSha256);

  clearGvlVendorOverview();

  if (!snapshot) {
    return;
  }

  try {
    const result = await browser.runtime.sendMessage({
      type: "list_gvl_vendors_for_snapshot",
      payload: {
        sha256: snapshot.sha256
      }
    });

    if (!result?.success) {
      throw new Error(result?.error ?? "list_gvl_vendors_for_snapshot_failed");
    }

    selectedSnapshotVendors = result.vendors ?? [];
    updateVendorOverviewSummary();
    renderVendorOverview();
  } catch (error) {
    gvlVendorOverviewEmpty.hidden = false;
    gvlVendorOverviewEmpty.textContent =
      "Vendoren-Übersicht konnte nicht geladen werden.";
    console.warn("VG-Observe GVL vendor overview failed", error);
  }
}

function renderVendorOverview() {
  gvlVendorOverviewList.textContent = "";

  if (!selectedSnapshotVendors.length) {
    gvlVendorOverviewEmpty.hidden = false;
    gvlVendorOverviewContent.hidden = true;
    gvlVendorOverviewEmpty.textContent =
      "Keine normalisierten Vendoren für diese Vendorliste vorhanden.";
    return;
  }

  gvlVendorOverviewEmpty.hidden = true;
  gvlVendorOverviewContent.hidden = false;

  for (const vendor of selectedSnapshotVendors) {
    const row = document.createElement("tr");

    row.tabIndex = 0;
    row.setAttribute("role", "button");
    row.addEventListener("click", async () => {
      await selectVendorFromOverview(vendor.vendorId);
    });
    row.addEventListener("keydown", async (event) => {
      if (event.key === "Enter" || event.key === " ") {
        event.preventDefault();
        await selectVendorFromOverview(vendor.vendorId);
      }
    });

    appendListCell(row, formatNullable(vendor.vendorId), "numeric");
    appendListCell(row, formatNullable(vendor.name));
    appendListCell(row, formatNullable(vendor.deletedDate));
    gvlVendorOverviewList.append(row);
  }
}

async function selectVendorFromOverview(vendorId) {
  if (vendorId === null || vendorId === undefined) {
    return;
  }

  gvlVendorIdInput.value = String(vendorId);
  await renderGvlVendorDetail();
}

function clearGvlVendorOverview() {
  gvlVendorOverviewList.textContent = "";
  selectedSnapshotVendors = [];
  gvlVendorOverviewEmpty.hidden = true;
  gvlVendorOverviewContent.hidden = true;
  gvlVendorOverviewDetails.open = false;
  updateVendorOverviewSummary();
}

function updateVendorOverviewSummary() {
  const count = selectedSnapshotVendors.length;

  gvlVendorOverviewSummary.textContent = count
    ? `Vendoren-Übersicht anzeigen (${count})`
    : "Vendoren-Übersicht anzeigen";
}

function updateRebuildActionState(summary) {
  const needsRebuild = doesSnapshotNeedNormalizedRebuild(summary);

  gvlRebuildNormalizedButton.disabled = !needsRebuild;

  if (!summary) {
    renderRebuildStatus("");
    return;
  }

  if (needsRebuild) {
    renderRebuildStatus("Reparatur möglich: normalisierte lokale Daten fehlen.");
    return;
  }

  renderRebuildStatus("Normalisierte lokale GVL-Daten sind verfügbar.");
}

function doesSnapshotNeedNormalizedRebuild(summary) {
  if (!summary) {
    return false;
  }

  const expectedVendorCount = Number(summary.snapshotVendorCount ?? 0);
  const normalizedVendorCount = Number(summary.normalizedVendorCount ?? 0);
  const normalizedRelationshipCount = Number(
    summary.normalizedVendorRelationshipCount ?? 0
  );

  if (expectedVendorCount > 0 && normalizedVendorCount < expectedVendorCount) {
    return true;
  }

  return normalizedVendorCount === 0 || normalizedRelationshipCount === 0;
}

function renderSummaryTable(summary) {
  const table = document.createElement("table");
  const body = document.createElement("tbody");
  const rows = [
    ["Vendorlisten-Version", formatNullable(summary.vendorListVersion)],
    ["Abrufzeitpunkt", formatNullable(summary.fetchedAt)],
    ["Quelle", formatNullable(summary.sourceUrl)],
    ["Anzahl Firmen/Vendoren", formatCount(summary.vendorCount)],
    [
      "Normalisierte Vendoren",
      formatCount(summary.normalizedVendorCount)
    ],
    ["Anzahl Zwecke/Purposes", formatCount(summary.purposeCount)],
    ["Anzahl Special Purposes", formatCount(summary.specialPurposeCount)],
    ["Anzahl Features", formatCount(summary.featureCount)],
    ["Anzahl Special Features", formatCount(summary.specialFeatureCount)],
    ["Anzahl Datenkategorien", formatCount(summary.dataCategoryCount)],
    [
      "Anzahl Vendor-Beziehungen",
      formatCount(summary.vendorRelationshipCount)
    ]
  ];

  table.className = "summary-table";

  for (const [label, value] of rows) {
    const row = document.createElement("tr");
    const labelCell = document.createElement("th");
    const valueCell = document.createElement("td");

    labelCell.scope = "row";
    labelCell.textContent = label;
    valueCell.textContent = value;
    row.append(labelCell, valueCell);
    body.append(row);
  }

  table.append(body);
  gvlSnapshotSummary.append(table);

  gvlTechnicalFields.textContent = JSON.stringify(
    summary.technicalFields ?? {},
    null,
    2
  );
  gvlDebugData.textContent = JSON.stringify(
    {
      sha256: summary.sha256 ?? null,
      eventType: summary.eventType ?? null,
      eventCapturedAt: summary.eventCapturedAt ?? null,
      diagnostics: summary.diagnostics ?? null
    },
    null,
    2
  );
}

function clearGvlSnapshotSummary() {
  gvlSnapshotSummary.textContent = "";
  gvlTechnicalFields.textContent = "";
  gvlDebugData.textContent = "";
  selectedSnapshotSummary = null;
}

function findGvlSnapshot(sha256) {
  if (!sha256) {
    return null;
  }

  return (
    gvlSnapshots.find((snapshot) => {
      return snapshot?.sha256 === sha256;
    }) ?? null
  );
}

function formatNullable(value) {
  if (value === null || value === undefined || value === "") {
    return "-";
  }

  return String(value);
}

function formatJsonValue(value) {
  if (value === null || value === undefined || value === "") {
    return "-";
  }

  return JSON.stringify(value);
}

function formatCount(value) {
  if (value === null || value === undefined) {
    return "0";
  }

  return String(value);
}

function shortenSha256(value) {
  if (!value) {
    return "-";
  }

  return `${String(value).slice(0, 12)}...`;
}
