(function () {
  const roots = document.querySelectorAll(".spp-portal[data-rest-url]");

  roots.forEach((root) => {
    const api = root.dataset.restUrl;
    const nonce = root.dataset.nonce;
    const permissions = new Set(JSON.parse(root.dataset.permissions || "[]"));
    const can = (permission) => permissions.has(permission);
    let state = {
      view: "deployments",
      deployments: [],
      templates: [],
      quota: null,
      selectedDeployment: null,
      error: null,
      loading: true
    };

    const request = async (path, options = {}) => {
      const response = await fetch(`${api}${path}`, {
        ...options,
        headers: {
          "Content-Type": "application/json",
          "X-WP-Nonce": nonce,
          ...(options.headers || {})
        }
      });

      const payload = await response.json().catch(() => null);
      if (!response.ok) {
        throw new Error(payload && payload.message ? payload.message : `Request failed with ${response.status}`);
      }
      return payload;
    };

    const load = async () => {
      state = { ...state, loading: true, error: null };
      render();
      try {
        const [deployments, templates, quota] = await Promise.all([
          request("/deployments"),
          request("/templates"),
          request("/quota")
        ]);
        state = { ...state, deployments, templates, quota, loading: false };
      } catch (error) {
        state = { ...state, error: error.message, loading: false };
      }
      render();
    };

    const lifecycle = async (id, action) => {
      try {
        const path = action === "delete" ? `/deployments/${id}` : `/deployments/${id}/${action}`;
        await request(path, { method: action === "delete" ? "DELETE" : "POST" });
        await load();
        state.selectedDeployment = action === "delete" ? null : await request(`/deployments/${id}`);
        state.view = action === "delete" ? "deployments" : "detail";
      } catch (error) {
        state = { ...state, error: error.message };
      }
      render();
    };

    const prolongDeployment = async (event, id) => {
      event.preventDefault();
      const form = new FormData(event.currentTarget);

      try {
        const deployment = await request(`/deployments/${id}/prolong`, {
          method: "POST",
          body: JSON.stringify({
            ttlHours: form.get("ttlHours") ? Number(form.get("ttlHours")) : undefined,
            neverExpire: form.get("neverExpire") === "1"
          })
        });
        await load();
        state = { ...state, view: "detail", selectedDeployment: deployment };
      } catch (error) {
        state = { ...state, error: error.message };
      }
      render();
    };

    const createDeployment = async (event) => {
      event.preventDefault();
      const form = new FormData(event.currentTarget);

      try {
        const deployment = await request("/deployments", {
          method: "POST",
          body: JSON.stringify({
            templateId: Number(form.get("templateId")),
            name: String(form.get("name")),
            ttlHours: form.get("ttlHours") ? Number(form.get("ttlHours")) : undefined,
            neverExpire: form.get("neverExpire") === "1"
          })
        });
        await load();
        state = { ...state, view: "detail", selectedDeployment: deployment };
      } catch (error) {
        state = { ...state, error: error.message };
      }
      render();
    };

    const shareDeployment = async (event, id) => {
      event.preventDefault();
      const form = new FormData(event.currentTarget);

      try {
        await request(`/deployments/${id}/shares`, {
          method: "POST",
          body: JSON.stringify({
            user: String(form.get("user"))
          })
        });
        state.selectedDeployment = await request(`/deployments/${id}`);
        state.error = null;
      } catch (error) {
        state = { ...state, error: error.message };
      }
      render();
    };

    const removeShare = async (id, userId) => {
      try {
        await request(`/deployments/${id}/shares/${userId}`, { method: "DELETE" });
        state.selectedDeployment = await request(`/deployments/${id}`);
        state.error = null;
      } catch (error) {
        state = { ...state, error: error.message };
      }
      render();
    };

    const statusBadge = (status) => `<span class="spp-badge ${status}">${status.replace("_", " ")}</span>`;

    const accessLabel = (deployment) => {
      if (deployment.accessType === "shared") {
        return '<span class="spp-badge SHARED">SHARED</span>';
      }

      if (deployment.accessType === "admin") {
        return '<span class="spp-badge ADMIN">ADMIN</span>';
      }

      return '<span class="spp-badge OWNER">OWNER</span>';
    };

    const resourceTypeLabel = (type) => type === "lxc" ? "LXC" : "VM";

    const actionButton = (permission, action, label, id, className = "", disabled = false) => {
      if (!can(permission)) {
        return "";
      }

      return `<button class="spp-button ${className}" data-action="${action}" data-id="${id}" ${disabled ? "disabled" : ""} type="button">${label}</button>`;
    };

    const ipList = (ips) => {
      if (!Array.isArray(ips) || ips.length === 0) {
        return "Pending";
      }

      return ips.map(escapeHtml).join(", ");
    };

    const dateTime = (value) => {
      if (!value) {
        return "Never";
      }

      return new Intl.DateTimeFormat(undefined, {
      dateStyle: "medium",
      timeStyle: "short"
      }).format(new Date(value.replace(" ", "T")));
    };

    const quotaLine = () => {
      if (!state.quota) {
        return "";
      }

      const userLimit = state.quota.userLimitMb > 0 ? `${state.quota.userLimitMb} MB` : "Unlimited";
      const globalLimit = state.quota.globalLimitMb > 0 ? `${state.quota.globalLimitMb} MB` : "Unlimited";

      return `
        <div class="spp-quota">
          <span>Your RAM: <strong>${state.quota.userUsedMb} MB</strong> / ${userLimit}</span>
          <span>Global RAM: <strong>${state.quota.globalUsedMb} MB</strong> / ${globalLimit}</span>
        </div>
      `;
    };

    const header = () => `
      <div class="spp-header">
        <div>
          <h2 class="spp-title">Support Provisioning Portal</h2>
          <p class="spp-subtitle">Template-based VM and LXC provisioning for support work.</p>
          ${quotaLine()}
        </div>
        <div class="spp-tabs">
          <button class="spp-button" data-view="deployments" type="button">Deployments</button>
          <button class="spp-button" data-view="templates" type="button">Templates</button>
          ${can("create_deployments") ? '<button class="spp-button spp-button-primary" data-view="create" type="button">Create</button>' : ""}
        </div>
      </div>
    `;

    const deploymentsView = () => {
      if (state.deployments.length === 0) {
        return '<div class="spp-panel"><p style="padding:16px;margin:0;">No deployments have been created yet.</p></div>';
      }

      return `
        <div class="spp-panel">
          <table class="spp-table">
            <thead>
              <tr><th>Name</th><th>Status</th><th>Access</th><th>Type</th><th>Template</th><th>IP addresses</th><th>Expires</th><th></th></tr>
            </thead>
            <tbody>
              ${state.deployments.map((deployment) => `
                <tr>
                  <td><strong>${escapeHtml(deployment.name)}</strong></td>
                  <td>${statusBadge(deployment.status)}</td>
                  <td>${accessLabel(deployment)}</td>
                  <td>${resourceTypeLabel(deployment.provisioningType)}</td>
                  <td>${escapeHtml(deployment.templateName)}</td>
                  <td>${ipList(deployment.ipAddresses)}</td>
                  <td>${dateTime(deployment.expiresAt)}</td>
                  <td><button class="spp-button" data-detail="${deployment.id}" type="button">Open</button></td>
                </tr>
              `).join("")}
            </tbody>
          </table>
        </div>
      `;
    };

    const templatesView = () => `
      <div class="spp-grid">
        ${state.templates.map((template) => `
          <article class="spp-card">
            <h3>${escapeHtml(template.name)}</h3>
            <p>${escapeHtml(template.description)}</p>
            <div class="spp-meta">
              <span>OS<strong>${template.osType}</strong></span>
              <span>Type<strong>${resourceTypeLabel(template.provisioningType)}</strong></span>
              <span>CPU<strong>${template.cpuCores} cores</strong></span>
              <span>Memory<strong>${template.memoryMb} MB</strong></span>
              <span>Disk<strong>${template.diskGb} GB</strong></span>
              <span>Default TTL<strong>${template.defaultTtlHours}h</strong></span>
            </div>
          </article>
        `).join("")}
      </div>
    `;

    const createView = () => {
      if (!can("create_deployments")) {
        return '<div class="spp-panel"><p style="padding:16px;margin:0;">You do not have permission to create deployments.</p></div>';
      }

      return `
        <div class="spp-panel" style="padding:16px;">
          <form class="spp-form" id="spp-create-form">
            <label>Template
              <select class="spp-select" name="templateId" required>
                ${state.templates.map((template) => `<option value="${template.id}">[${resourceTypeLabel(template.provisioningType)}] ${escapeHtml(template.name)}</option>`).join("")}
              </select>
            </label>
            <label>Deployment name
              <input class="spp-input" name="name" minlength="3" maxlength="160" required placeholder="pbx-repro-case-1842">
            </label>
            <label>TTL hours
              <input class="spp-input" name="ttlHours" type="number" min="1" max="720" placeholder="Use template default">
            </label>
            <label class="spp-check">
              <input name="neverExpire" type="checkbox" value="1">
              <span>Never expire</span>
            </label>
            <button class="spp-button spp-button-primary" type="submit">Create Deployment</button>
          </form>
        </div>
      `;
    };

    const detailView = () => {
      const deployment = state.selectedDeployment;
      if (!deployment) {
        return deploymentsView();
      }

      const shares = Array.isArray(deployment.shares) ? deployment.shares : [];

      return `
        <div class="spp-panel" style="padding:16px;">
          ${deployment.status === "EXPIRED" ? `
            <div class="spp-warning">
              This deployment is expired${deployment.errorMessage ? "" : " and has been stopped"}. Prolong its TTL to unlock start actions, or delete it when the data is no longer needed.
              ${deployment.errorMessage ? `<br><strong>Stop warning:</strong> ${escapeHtml(deployment.errorMessage)}` : ""}
            </div>
          ` : ""}
          <div class="spp-header">
            <div>
              <button class="spp-button" data-view="deployments" type="button">Back</button>
              <h2 class="spp-title" style="margin-top:12px;">${escapeHtml(deployment.name)}</h2>
              ${statusBadge(deployment.status)}
            </div>
            <div class="spp-actions">
              ${actionButton("start_deployments", "start", "Start", deployment.id, "spp-button-primary", deployment.status === "RUNNING" || deployment.status === "EXPIRED")}
              ${actionButton("stop_deployments", "stop", "Stop", deployment.id, "", deployment.status === "STOPPED" || deployment.status === "EXPIRED")}
              ${actionButton("refresh_deployment_ips", "refresh-ips", "Refresh IPs", deployment.id, "", deployment.status === "DELETED")}
              ${deployment.canDelete ? actionButton("delete_deployments", "delete", "Delete", deployment.id, "spp-button-danger", deployment.status === "DELETED") : ""}
            </div>
          </div>
          <div class="spp-meta">
            <span>Template<strong>${escapeHtml(deployment.templateName)}</strong></span>
            <span>Type<strong>${resourceTypeLabel(deployment.provisioningType)}</strong></span>
            <span>Requested by<strong>${escapeHtml(deployment.requestedByName)}</strong></span>
            <span>Access<strong>${deployment.accessType ? escapeHtml(deployment.accessType) : "Owner"}</strong></span>
            <span>Proxmox ID<strong>${deployment.proxmoxResourceId || deployment.proxmoxVmId || "Pending"}</strong></span>
            <span>IP addresses<strong>${ipList(deployment.ipAddresses)}</strong></span>
            <span>CPU<strong>${deployment.cpuCores} cores</strong></span>
            <span>Memory<strong>${deployment.memoryMb} MB</strong></span>
            <span>Disk<strong>${deployment.diskGb} GB</strong></span>
            <span>Created<strong>${dateTime(deployment.createdAt)}</strong></span>
            <span>Expires<strong>${dateTime(deployment.expiresAt)}</strong></span>
          </div>
          ${can("prolong_deployments") ? `
            <form class="spp-prolong-form" data-prolong-form="${deployment.id}">
              <h3>Prolong TTL</h3>
              <label>TTL hours
                <input class="spp-input" name="ttlHours" type="number" min="1" max="720" placeholder="Hours from now">
              </label>
              <label class="spp-check">
                <input name="neverExpire" type="checkbox" value="1">
                <span>Never expire</span>
              </label>
              <button class="spp-button spp-button-primary" type="submit">Prolong</button>
            </form>
          ` : ""}
          ${deployment.canShare ? `
            <div class="spp-share-panel">
              <h3>Shared Access</h3>
              <div class="spp-share-list">
                ${shares.length === 0 ? '<p>No users have shared access.</p>' : shares.map((share) => `
                  <div class="spp-share-row">
                    <span>
                      <strong>${escapeHtml(share.displayName || share.userLogin)}</strong>
                      <small>${escapeHtml(share.userLogin)}${share.userEmail ? ` - ${escapeHtml(share.userEmail)}` : ""}</small>
                    </span>
                    <button class="spp-button" data-remove-share="${share.id}" data-id="${deployment.id}" type="button">Remove</button>
                  </div>
                `).join("")}
              </div>
              <form class="spp-share-form" data-share-form="${deployment.id}">
                <label>Share with user login or email
                  <input class="spp-input" name="user" required>
                </label>
                <button class="spp-button spp-button-primary" type="submit">Share</button>
              </form>
            </div>
          ` : ""}
        </div>
      `;
    };

    const render = () => {
      root.innerHTML = `
        ${header()}
        ${state.error ? `<p class="spp-error">${escapeHtml(state.error)}</p>` : ""}
        ${state.loading ? '<div class="spp-panel"><p style="padding:16px;margin:0;">Loading...</p></div>' : ""}
        ${!state.loading && state.view === "deployments" ? deploymentsView() : ""}
        ${!state.loading && state.view === "templates" ? templatesView() : ""}
        ${!state.loading && state.view === "create" ? createView() : ""}
        ${!state.loading && state.view === "detail" ? detailView() : ""}
      `;

      root.querySelectorAll("[data-view]").forEach((button) => {
        button.addEventListener("click", () => {
          state = { ...state, view: button.dataset.view, selectedDeployment: null };
          render();
        });
      });

      root.querySelectorAll("[data-detail]").forEach((button) => {
        button.addEventListener("click", async () => {
          try {
            state.selectedDeployment = await request(`/deployments/${button.dataset.detail}`);
            state.view = "detail";
          } catch (error) {
            state.error = error.message;
          }
          render();
        });
      });

      root.querySelectorAll("[data-action]").forEach((button) => {
        button.addEventListener("click", () => lifecycle(Number(button.dataset.id), button.dataset.action));
      });

      root.querySelectorAll("[data-remove-share]").forEach((button) => {
        button.addEventListener("click", () => removeShare(Number(button.dataset.id), Number(button.dataset.removeShare)));
      });

      const form = root.querySelector("#spp-create-form");
      if (form) {
        form.addEventListener("submit", createDeployment);
        const neverExpire = form.querySelector('input[name="neverExpire"]');
        const ttlHours = form.querySelector('input[name="ttlHours"]');
        if (neverExpire && ttlHours) {
          neverExpire.addEventListener("change", () => {
            ttlHours.disabled = neverExpire.checked;
            if (neverExpire.checked) {
              ttlHours.value = "";
            }
          });
        }
      }

      root.querySelectorAll("[data-prolong-form]").forEach((form) => {
        form.addEventListener("submit", (event) => prolongDeployment(event, Number(form.dataset.prolongForm)));
        const neverExpire = form.querySelector('input[name="neverExpire"]');
        const ttlHours = form.querySelector('input[name="ttlHours"]');
        if (neverExpire && ttlHours) {
          neverExpire.addEventListener("change", () => {
            ttlHours.disabled = neverExpire.checked;
            if (neverExpire.checked) {
              ttlHours.value = "";
            }
          });
        }
      });

      root.querySelectorAll("[data-share-form]").forEach((form) => {
        form.addEventListener("submit", (event) => shareDeployment(event, Number(form.dataset.shareForm)));
      });
    };

    const escapeHtml = (value) => String(value).replace(/[&<>"']/g, (character) => ({
      "&": "&amp;",
      "<": "&lt;",
      ">": "&gt;",
      '"': "&quot;",
      "'": "&#039;"
    }[character]));

    load();
  });
})();
