(() => {
  "use strict";

  const $ = (id) => document.getElementById(id);
  const STEPS = [
    ["detected", "1 Prepare"],
    ["cleanup", "2 Manual cleanup"],
    ["extract", "3 Updated content"],
    ["finalize", "4 Finish"],
  ];
  let current = null;
  let root = "";
  let busy = false;
  let errorText = "";

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

  function phaseIndex(phase) {
    if (phase === "complete") return STEPS.length;
    return Math.max(0, STEPS.findIndex(([key]) => key === phase));
  }

  function setBusy(nextBusy, label = "Working...") {
    busy = Boolean(nextBusy);
    ["evoUpdatePrimary", "evoUpdateSecondary", "evoUpdateOpenFolder", "evoUpdateClose", "evoUpdateCloseX"].forEach((id) => {
      const button = $(id);
      if (button) button.disabled = busy;
    });
    const primary = $("evoUpdatePrimary");
    if (primary && busy) primary.textContent = label;
  }

  function setButton(id, { label = "", hidden = false, disabled = false } = {}) {
    const button = $(id);
    if (!button) return;
    button.hidden = Boolean(hidden);
    button.disabled = Boolean(disabled || busy);
    if (label) button.textContent = label;
  }

  function renderSteps(phase) {
    const index = phaseIndex(phase);
    const target = $("evoUpdateSteps");
    if (!target) return;
    target.innerHTML = STEPS.map(([, label], itemIndex) => {
      const className = itemIndex < index ? "is-complete" : (itemIndex === index ? "is-active" : "");
      return `<li class="evo-update-step ${className}">${escapeHtml(label)}</li>`;
    }).join("");
  }

  function packageRows() {
    const workflow = current?.workflow || {};
    const conflict = current?.conflict || {};
    return {
      obsolete: workflow.obsoletePackagePath || conflict.obsoleteDisabledPath || "",
      active: workflow.activePackagePath || conflict.activePath || current?.cleanup?.activePackagePath || "",
    };
  }

  function renderDetected() {
    const paths = packageRows();
    $("evoUpdateSubtitle").textContent = "Steam installed a new content package";
    $("evoUpdateContent").innerHTML = `
      <h3>Advanced content must be refreshed</h3>
      <p>LiveryLab found a new active <code>content.kspkg</code> next to the package previously disabled for Advanced mode.</p>
      <div class="evo-update-warning">Close AC EVO before continuing. LiveryLab will remember active liveries, remove their managed game copies and SavedCars, clean runtime hooks and mark the old extraction as outdated.</div>
      <ul class="evo-update-checklist">
        <li><strong>New package — keep:</strong><br>${escapeHtml(paths.active)}</li>
        <li><strong>Old disabled package — remove later:</strong><br>${escapeHtml(paths.obsolete)}</li>
      </ul>`;
    setButton("evoUpdateOpenFolder", { hidden: true });
    setButton("evoUpdateSecondary", { hidden: true });
    setButton("evoUpdatePrimary", { label: "Prepare EVO Update" });
  }

  function renderCleanup() {
    const cleanup = current?.cleanup || {};
    const obsoleteReady = !cleanup.obsoletePackageExists;
    const folders = Array.isArray(cleanup.folders) ? cleanup.folders : [];
    const cleanupRoot = current?.root || root;
    $("evoUpdateSubtitle").textContent = cleanup.ready ? "Manual cleanup verified" : "Remove the old package and extracted folders";
    $("evoUpdateContent").innerHTML = `
      <h3>${cleanup.ready ? "Cleanup complete" : "Manual cleanup required"}</h3>
      <p>Open the AC EVO folder and manually remove every item still marked below. LiveryLab will not delete, rename or move these files.</p>
      <div class="evo-update-warning">The listed folders contain the old full extraction. Remove them only after the preparation step. Unrelated manual loose mods stored inside these folders will also be removed.</div>
      <p class="evo-update-folder-root"><strong>Extracted folders inside:</strong><br>${escapeHtml(cleanupRoot)}</p>
      <ul class="evo-update-checklist evo-update-cleanup-list">
        <li class="evo-update-cleanup-package ${obsoleteReady ? "is-ready" : ""}"><strong>${obsoleteReady ? "Removed" : "Delete manually"}:</strong><br>${escapeHtml(cleanup.obsoletePackagePath || "Old disabled package")}</li>
        ${folders.map((row) => `<li class="${row.exists ? "" : "is-ready"}"><strong>${row.exists ? "Delete folder" : "Removed"}:</strong><br><code>${escapeHtml(row.name || "")}</code></li>`).join("")}
      </ul>`;
    setButton("evoUpdateOpenFolder", { hidden: false });
    setButton("evoUpdateSecondary", { hidden: true });
    setButton("evoUpdatePrimary", { label: cleanup.ready ? "Continue" : "Check Again" });
  }

  function renderExtract() {
    const active = current?.cleanup?.activePackagePath || packageRows().active;
    const activeLiveries = current?.activeLiveries || [];
    $("evoUpdateSubtitle").textContent = "Choose how to continue";
    $("evoUpdateContent").innerHTML = `
      <h3>Updated package is ready</h3>
      <p>Continue with Advanced to extract the updated content, or remain on the Official runtime without extracting.</p>
      <ul class="evo-update-checklist">
        <li><strong>Updated package:</strong><br>${escapeHtml(active)}</li>
        <li><strong>Previously active Advanced liveries:</strong> ${escapeHtml(activeLiveries.length)}</li>
      </ul>`;
    setButton("evoUpdateOpenFolder", { hidden: true });
    setButton("evoUpdateSecondary", { label: "Continue with Official", hidden: false });
    setButton("evoUpdatePrimary", { label: "Extract Updated Content" });
  }

  function renderFinalize() {
    const activeLiveries = current?.activeLiveries || [];
    $("evoUpdateSubtitle").textContent = "Updated extraction verified";
    $("evoUpdateContent").innerHTML = `
      <h3>Finish Advanced setup</h3>
      <p>LiveryLab will disable the updated package, verify the Advanced runtime and restore the liveries that were active before the EVO update.</p>
      <ul class="evo-update-checklist">
        <li><strong>Liveries to restore:</strong> ${escapeHtml(activeLiveries.length)}</li>
      </ul>`;
    setButton("evoUpdateOpenFolder", { hidden: true });
    setButton("evoUpdateSecondary", { hidden: true });
    setButton("evoUpdatePrimary", { label: "Finish Advanced Setup" });
  }

  function renderComplete() {
    const workflow = current?.workflow || {};
    const target = workflow.targetWorkflow || "advanced";
    const restored = Array.isArray(workflow.restoredLiveries) ? workflow.restoredLiveries.filter((row) => row.restored).length : 0;
    $("evoUpdateSubtitle").textContent = "EVO update workflow completed";
    $("evoUpdateContent").innerHTML = `
      <h3>${target === "official" ? "Official runtime is ready" : "Advanced runtime is ready"}</h3>
      <p>The old update state was cleaned and the selected runtime was prepared successfully.</p>
      ${target === "advanced" ? `<p>${escapeHtml(restored)} previously active liveries were restored.</p>` : ""}`;
    setButton("evoUpdateOpenFolder", { hidden: true });
    setButton("evoUpdateSecondary", { hidden: true });
    setButton("evoUpdatePrimary", { label: target === "official" ? "Open Official" : "Open Advanced" });
    setButton("evoUpdateClose", { label: "Close" });
  }

  function render() {
    const modal = $("evoUpdateModal");
    if (!modal || !current) return;
    const phase = current.phase || current.workflow?.phase || "detected";
    renderSteps(phase);
    const error = $("evoUpdateError");
    error.hidden = !errorText;
    error.textContent = errorText;
    if (phase === "cleanup") renderCleanup();
    else if (phase === "extract") renderExtract();
    else if (phase === "finalize") renderFinalize();
    else if (phase === "complete") renderComplete();
    else renderDetected();
    modal.hidden = false;
  }

  function close() {
    if (busy) return;
    const modal = $("evoUpdateModal");
    if (modal) modal.hidden = true;
  }

  async function api(name, ...args) {
    const fn = window.pywebview?.api?.[name];
    if (typeof fn !== "function") throw new Error(`Missing API: ${name}`);
    const result = await fn(...args);
    if (!result?.ok) throw new Error(result?.message || result?.error || `${name} failed`);
    return result.data || {};
  }

  async function open(nextRoot = "") {
    root = String(nextRoot || root || "").trim();
    if (!root) return false;
    try {
      current = await api("get_evo_update_workflow", root);
      if (!current.available) return false;
      errorText = "";
      render();
      return true;
    } catch (error) {
      errorText = error?.message || String(error);
      return false;
    }
  }

  async function prepare() {
    setBusy(true, "Preparing...");
    errorText = "";
    try {
      current = await api("start_evo_update_workflow", root);
      current = await api("prepare_evo_update_workflow", root);
    } catch (error) {
      errorText = error?.message || String(error);
    } finally {
      setBusy(false);
      render();
    }
  }

  async function checkCleanup() {
    setBusy(true, "Checking...");
    errorText = "";
    try {
      current = await api("inspect_evo_update_cleanup", root);
    } catch (error) {
      errorText = error?.message || String(error);
    } finally {
      setBusy(false);
      render();
    }
  }

  async function withHostAction(action) {
    const modal = $("evoUpdateModal");
    if (modal) modal.hidden = true;
    try {
      return await action();
    } finally {
      if (modal && current?.phase !== "complete") modal.hidden = false;
    }
  }

  async function extractUpdatedContent() {
    setBusy(true, "Starting extraction...");
    errorText = "";
    try {
      const host = window.LiveryLabEvoUpdateHost;
      if (!host?.extractUpdatedContent) throw new Error("The update extraction host is unavailable.");
      const result = await withHostAction(() => host.extractUpdatedContent({ root, packagePath: current?.cleanup?.activePackagePath || packageRows().active }));
      if (!result?.ok) throw new Error(result?.message || "Updated content extraction failed.");
      current = await api("mark_evo_update_extracted", root);
    } catch (error) {
      errorText = error?.message || String(error);
    } finally {
      setBusy(false);
      render();
    }
  }

  async function finish(targetWorkflow) {
    setBusy(true, targetWorkflow === "official" ? "Preparing Official..." : "Finishing Advanced...");
    errorText = "";
    try {
      const host = window.LiveryLabEvoUpdateHost;
      if (!host?.prepareRuntime) throw new Error("The runtime preparation host is unavailable.");
      const prepared = await withHostAction(() => host.prepareRuntime(targetWorkflow));
      if (!prepared?.ready) throw new Error(prepared?.reason || `${targetWorkflow} runtime preparation was not completed.`);
      let restored = [];
      if (targetWorkflow === "advanced") {
        restored = await host.restoreActiveLiveries(current?.activeLiveries || []);
        const failed = restored.filter((row) => !row.restored);
        if (failed.length) throw new Error(`${failed.length} previously active liveries could not be restored.`);
      }
      const completed = await api("complete_evo_update_workflow", { root, targetWorkflow, restoredLiveries: restored });
      current = { ...completed, phase: "complete", workflow: completed.workflow || {} };
    } catch (error) {
      errorText = error?.message || String(error);
    } finally {
      setBusy(false);
      render();
    }
  }

  async function primaryAction() {
    const phase = current?.phase || current?.workflow?.phase || "detected";
    if (phase === "detected") return prepare();
    if (phase === "cleanup") return checkCleanup();
    if (phase === "extract") return extractUpdatedContent();
    if (phase === "finalize") return finish("advanced");
    if (phase === "complete") {
      const target = current?.workflow?.targetWorkflow || "advanced";
      close();
      return window.LiveryLabEvoUpdateHost?.enterWorkflow?.(target);
    }
  }

  async function secondaryAction() {
    if ((current?.phase || "") === "extract") await finish("official");
  }

  async function openFolder() {
    try {
      await api("open_folder", root);
    } catch (error) {
      errorText = error?.message || String(error);
      render();
    }
  }

  function init() {
    document.addEventListener("click", (event) => {
      const action = event.target?.closest?.("[data-evo-update-action]")?.dataset?.evoUpdateAction;
      if (!action) return;
      event.preventDefault();
      if (action === "close") close();
      else if (action === "primary") primaryAction();
      else if (action === "secondary") secondaryAction();
      else if (action === "open-folder") openFolder();
    });
  }

  init();
  window.LiveryLabEvoUpdateWorkflow = {
    open,
    close,
    checkAtStartup: open,
    isOpen: () => !$("evoUpdateModal")?.hidden,
  };
  if (window.LiveryLabEvoUpdateStartupRoot) {
    Promise.resolve().then(() => open(window.LiveryLabEvoUpdateStartupRoot));
  }
})();
