"use strict";

const EVIDENCE_MAINTENANCE_SOURCE = "dashboard";
const EVIDENCE_MAINTENANCE_HEARTBEAT_MS = 5 * 1000;

const dashboardStatus = document.getElementById("dashboard-status");
const totalCount = document.getElementById("total-count");
const lockedCount = document.getElementById("locked-count");
const unlockedCount = document.getElementById("unlocked-count");
const maintenanceWriteSuspend = document.getElementById(
  "maintenance-write-suspend"
);
const maintenanceSource = document.getElementById("maintenance-source");
const maintenanceHeartbeat = document.getElementById("maintenance-heartbeat");
const maintenanceExpires = document.getElementById("maintenance-expires");
const lockAllButton = document.getElementById("lock-all-button");
const unlockAllButton = document.getElementById("unlock-all-button");
const gvlFetchOfficialButton = document.getElementById(
  "gvl-fetch-official-button"
);
const gvlImportButton = document.getElementById("gvl-import-button");
const evidenceDeleteButton = document.getElementById("evidence-delete-button");
const adminStatus = document.getElementById("admin-status");
const gvlImportFileInput = document.createElement("input");

gvlImportFileInput.type = "file";
gvlImportFileInput.accept = ".json,application/json";
gvlImportFileInput.hidden = true;

let evidenceMaintenanceHeartbeatId = null;

const storeCells = {
  consent_states: document.getElementById("store-consent-states"),
  consent_events: document.getElementById("store-consent-events"),
  observed_requests: document.getElementById("store-observed-requests"),
  gvl_snapshots: document.getElementById("store-gvl-snapshots"),
  gvl_snapshot_events: document.getElementById("store-gvl-snapshot-events")
};

document.addEventListener("DOMContentLoaded", async () => {
  document.body.appendChild(gvlImportFileInput);

  await startEvidenceMaintenanceMode();
  evidenceMaintenanceHeartbeatId = setInterval(() => {
    void refreshEvidenceMaintenanceMode();
  }, EVIDENCE_MAINTENANCE_HEARTBEAT_MS);

  lockAllButton.addEventListener("click", async () => {
    await handleLockAllClick();
  });

  unlockAllButton.addEventListener("click", async () => {
    await handleUnlockAllClick();
  });

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

  gvlImportButton.addEventListener("click", () => {
    gvlImportFileInput.value = "";
    gvlImportFileInput.click();
  });

  gvlImportFileInput.addEventListener("change", async () => {
    const file = gvlImportFileInput.files?.[0] ?? null;

    if (!file) {
      return;
    }

    await importGvlFile(file);
  });

  evidenceDeleteButton.addEventListener("click", async () => {
    await handleEvidenceDeleteClick();
  });

  await renderEvidenceStatus();
});

window.addEventListener("beforeunload", () => {
  endEvidenceMaintenanceMode();
});

window.addEventListener("pagehide", () => {
  endEvidenceMaintenanceMode();
});

async function startEvidenceMaintenanceMode() {
  try {
    const status = await sendEvidenceMaintenanceMessage(
      "start_evidence_maintenance_session"
    );

    renderEvidenceMaintenanceStatus(status);
  } catch (error) {
    renderEvidenceMaintenanceUnavailable();
    console.warn("VendorGet-IV maintenance start failed", error);
  }
}

async function refreshEvidenceMaintenanceMode() {
  try {
    const status = await sendEvidenceMaintenanceMessage(
      "refresh_evidence_maintenance_session"
    );

    renderEvidenceMaintenanceStatus(status);
  } catch (error) {
    renderEvidenceMaintenanceUnavailable();
    console.warn("VendorGet-IV maintenance heartbeat failed", error);
  }
}

function endEvidenceMaintenanceMode() {
  if (evidenceMaintenanceHeartbeatId !== null) {
    clearInterval(evidenceMaintenanceHeartbeatId);
    evidenceMaintenanceHeartbeatId = null;
  }

  void sendEvidenceMaintenanceMessage("end_evidence_maintenance_session").catch(
    (error) => {
      console.warn("VendorGet-IV maintenance end failed", error);
    }
  );
}

async function sendEvidenceMaintenanceMessage(type) {
  const status = await browser.runtime.sendMessage({
    type: type,
    payload: {
      source: EVIDENCE_MAINTENANCE_SOURCE
    }
  });

  if (!status?.success) {
    throw new Error(status?.error ?? `${type}_failed`);
  }

  return status;
}

function renderEvidenceMaintenanceStatus(status) {
  maintenanceWriteSuspend.textContent = status.evidenceWriteSuspended
    ? "aktiv"
    : "inaktiv";
  maintenanceSource.textContent = status.source ?? "-";
  maintenanceHeartbeat.textContent = formatMaintenanceTimestamp(
    status.lastHeartbeatAt
  );
  maintenanceExpires.textContent = formatMaintenanceTimestamp(status.expiresAt);
}

function renderEvidenceMaintenanceUnavailable() {
  maintenanceWriteSuspend.textContent = "unbekannt";
  maintenanceSource.textContent = "-";
  maintenanceHeartbeat.textContent = "-";
  maintenanceExpires.textContent = "-";
}

async function renderEvidenceStatus() {
  try {
    const status = await browser.runtime.sendMessage({
      type: "get_evidence_retention_status"
    });

    if (!status?.success) {
      throw new Error(status?.error ?? "get_evidence_retention_status_failed");
    }

    totalCount.textContent = String(status.totalCount);
    lockedCount.textContent = String(status.lockedCount);
    unlockedCount.textContent = String(status.unlockedCount);

    renderStoreCounts(status.storeCounts ?? {});
    renderStatusMessage("Evidence status loaded");
  } catch (error) {
    renderStatusMessage("Evidence status could not be loaded");
    console.warn("VendorGet-IV dashboard status failed", error);
  }
}

function renderStoreCounts(storeCounts) {
  for (const [storeName, cell] of Object.entries(storeCells)) {
    cell.textContent = String(storeCounts[storeName] ?? 0);
  }
}

async function fetchOfficialGvl() {
  gvlFetchOfficialButton.disabled = true;
  renderAdminStatus("Fetching official IAB GVL...");

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

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

    await renderEvidenceStatus();
    renderAdminStatus(
      "Fetched successfully - " +
        `${result.alreadyKnown ? "already known" : "newly stored"} - ` +
        `vendorListVersion ${result.vendorListVersion ?? "n/a"} - ` +
        `sha256 ${shortenSha256(result.sha256)}`
    );
  } catch (error) {
    renderAdminStatus("Official GVL fetch failed");
    console.warn("VendorGet-IV official GVL fetch failed", error);
  } finally {
    gvlFetchOfficialButton.disabled = false;
  }
}

async function importGvlFile(file) {
  gvlImportButton.disabled = true;
  renderAdminStatus("Import läuft...");

  try {
    const fileContent = await readFileAsText(file);
    const rawJson = JSON.parse(fileContent);

    if (!isGvlImportCandidate(rawJson)) {
      throw new Error("invalid_gvl_json");
    }

    const result = await browser.runtime.sendMessage({
      type: "gvl_import_json",
      payload: {
        rawJson: rawJson,
        sourceUrl: "local-file-import"
      }
    });

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

    await renderEvidenceStatus();
    renderAdminStatus(
      `${result.alreadyKnown ? "already known" : "imported"} - ` +
        `vendorListVersion ${result.vendorListVersion ?? "n/a"} - ` +
        `sha256 ${shortenSha256(result.sha256)}`
    );
  } catch (error) {
    renderAdminStatus("Import fehlgeschlagen");
    console.warn("VendorGet-IV GVL import failed", error);
  } finally {
    gvlImportButton.disabled = false;
  }
}

function readFileAsText(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onerror = () => reject(reader.error);
    reader.onload = () => resolve(reader.result);
    reader.readAsText(file);
  });
}

function isGvlImportCandidate(value) {
  return (
    value &&
    typeof value === "object" &&
    !Array.isArray(value) &&
    value.vendorListVersion !== undefined &&
    value.vendors &&
    typeof value.vendors === "object" &&
    !Array.isArray(value.vendors)
  );
}

async function handleEvidenceDeleteClick() {
  evidenceDeleteButton.disabled = true;

  try {
    const status = await getEvidenceRetentionStatus();

    const confirmed = confirm(
      "Alle lokal gespeicherten VG-IV-Evidenzdaten wirklich löschen?"
    );

    if (!confirmed) {
      renderAdminStatus("Löschung abgebrochen");
      return;
    }

    if (status.lockedCount === 0) {
      await deleteAllEvidenceDatabase();
      await renderEvidenceStatus();
      renderAdminStatus("Evidenzdaten gelöscht");
      return;
    }

    const deleteLockedRecords = confirm(
      `Achtung: ${status.lockedCount} Datensätze wurden als ` +
        "DSGVO-/DSAR-relevant markiert. Sollen auch diese Datensätze " +
        "wirklich gelöscht werden?"
    );

    if (deleteLockedRecords) {
      await deleteAllEvidenceDatabase();
      await renderEvidenceStatus();
      renderAdminStatus("Evidenzdaten gelöscht");
      return;
    }

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

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

    await renderEvidenceStatus();
    renderAdminStatus(
      `${result.deletedCount} Datensätze gelöscht, ` +
        `${result.keptLockedCount} gesperrte Datensätze behalten`
    );
  } catch (error) {
    renderAdminStatus("Löschung fehlgeschlagen");
    console.warn("VendorGet-IV evidence delete failed", error);
  } finally {
    evidenceDeleteButton.disabled = false;
  }
}

async function getEvidenceRetentionStatus() {
  const status = await browser.runtime.sendMessage({
    type: "get_evidence_retention_status"
  });

  if (!status?.success) {
    throw new Error(status?.error ?? "get_evidence_retention_status_failed");
  }

  return status;
}

async function deleteAllEvidenceDatabase() {
  const result = await browser.runtime.sendMessage({
    type: "delete_all_evidence_database"
  });

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

async function handleLockAllClick() {
  const confirmed = confirm(
    "Alle vorhandenen VG-IV-Evidenzdatensätze als DSGVO-/DSAR-relevant markieren?"
  );

  if (!confirmed) {
    renderStatusMessage("Record lock update cancelled");
    return;
  }

  await runRecordLockAction({
    type: "lock_all_evidence_records",
    payload: {
      reason: "dsar_used",
      note: null
    }
  });
}

async function handleUnlockAllClick() {
  const confirmed = confirm(
    "Alle VG-IV-Evidenzsperren wirklich entfernen?"
  );

  if (!confirmed) {
    renderStatusMessage("Record lock update cancelled");
    return;
  }

  await runRecordLockAction({
    type: "unlock_all_evidence_records"
  });
}

async function runRecordLockAction(message) {
  setRecordLockButtonsDisabled(true);

  try {
    const result = await browser.runtime.sendMessage(message);

    if (!result?.success) {
      throw new Error(result?.error ?? `${message.type}_failed`);
    }

    await renderEvidenceStatus();
  } catch (error) {
    renderStatusMessage("Record lock update failed");
    console.warn("VendorGet-IV dashboard record lock update failed", error);
  } finally {
    setRecordLockButtonsDisabled(false);
  }
}

function setRecordLockButtonsDisabled(disabled) {
  lockAllButton.disabled = disabled;
  unlockAllButton.disabled = disabled;
}

function renderStatusMessage(message) {
  dashboardStatus.textContent = message;
}

function renderAdminStatus(message) {
  adminStatus.textContent = message;
}

function shortenSha256(value) {
  if (!value) {
    return "n/a";
  }

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

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

  return value;
}
