import type {DocumentActionComponent} from "sanity";
import {useClient} from "sanity";

const API_VERSION = "2026-03-26";
const POLL_INTERVAL_MS = 750;
const PUBLISH_TIMEOUT_MS = 20_000;
const SYNC_TIMEOUT_MS = 45_000;

type SyncPhase = "publishing" | "syncing" | "success" | "failed";

type StatusResponse = {
  status?: "waiting" | "pending" | "success" | "failed";
  variantCount?: number;
  variants?: Array<{title?: string; amount?: number; currency_code?: string}>;
  error?: string | null;
};

type SyncPopup = {
  update: (phase: SyncPhase, message: string, variants?: StatusResponse["variants"]) => void;
};

function wait(ms: number) {
  return new Promise((resolve) => window.setTimeout(resolve, ms));
}

function getMedusaUrl() {
  const configuredUrl = (process.env.SANITY_STUDIO_MEDUSA_URL || "").replace(/\/+$/, "");
  if (configuredUrl) return configuredUrl;
  return window.location.hostname === "localhost" ? "http://localhost:9000" : "https://api.stylunique.fr";
}

async function waitForPublishedRevision(
  client: ReturnType<typeof useClient>,
  documentId: string,
  previousRevision?: string,
) {
  const deadline = Date.now() + PUBLISH_TIMEOUT_MS;

  while (Date.now() < deadline) {
    const published = await client.fetch<{_rev?: string} | null>(
      `*[_type == "product" && _id == $id][0]{_rev}`,
      {id: documentId},
      {perspective: "published"},
    );

    if (published?._rev && published._rev !== previousRevision) {
      return published._rev;
    }

    await wait(POLL_INTERVAL_MS);
  }

  throw new Error("La publication Sanity n'a pas ete confirmee dans le delai imparti.");
}

async function waitForMedusaSync(documentId: string, revision: string) {
  const deadline = Date.now() + SYNC_TIMEOUT_MS;
  const endpoint = new URL("/custom/sanity/products/status", getMedusaUrl());
  endpoint.searchParams.set("documentId", documentId);
  endpoint.searchParams.set("revision", revision);

  while (Date.now() < deadline) {
    const response = await fetch(endpoint, {cache: "no-store"});
    const result = (await response.json().catch(() => ({}))) as StatusResponse;

    if (result.status === "success") return result;
    if (result.status === "failed") {
      throw new Error(result.error || "La synchronisation Medusa a echoue.");
    }
    if (!response.ok && response.status !== 202 && response.status !== 409) {
      throw new Error(`Medusa ne repond pas correctement (${response.status}).`);
    }

    await wait(POLL_INTERVAL_MS);
  }

  throw new Error(
    "Medusa n'a pas recu cette publication. Verifiez que le webhook Sanity utilise /custom/sanity/products (sans /store).",
  );
}

function formatPrice(amount?: number, currencyCode = "eur") {
  if (typeof amount !== "number") return "Prix absent";
  return new Intl.NumberFormat("fr-FR", {style: "currency", currency: currencyCode.toUpperCase()}).format(amount / 100);
}

function createSyncPopup(): SyncPopup {
  const dialog = document.createElement("dialog");
  const container = document.createElement("div");
  const status = document.createElement("strong");
  const message = document.createElement("p");
  const variantsList = document.createElement("div");
  const closeButton = document.createElement("button");

  dialog.setAttribute("aria-labelledby", "medusa-sync-status");
  Object.assign(dialog.style, {
    width: "min(520px, calc(100vw - 32px))",
    border: "1px solid #3f434f",
    borderRadius: "8px",
    background: "#17181d",
    color: "#f1f1f3",
    padding: "0",
    boxShadow: "0 18px 60px rgba(0, 0, 0, 0.45)",
  });
  Object.assign(container.style, {display: "grid", gap: "16px", padding: "24px"});
  status.id = "medusa-sync-status";
  status.style.fontSize = "18px";
  Object.assign(message.style, {margin: "0", lineHeight: "1.5", color: "#c7c8ce"});
  Object.assign(variantsList.style, {display: "grid", gap: "8px"});
  closeButton.type = "button";
  closeButton.textContent = "Fermer";
  closeButton.disabled = true;
  Object.assign(closeButton.style, {
    justifySelf: "end",
    border: "1px solid #5b6070",
    borderRadius: "4px",
    background: "#25272e",
    color: "#f1f1f3",
    padding: "9px 14px",
    font: "inherit",
    cursor: "pointer",
  });
  closeButton.addEventListener("click", () => {
    dialog.close();
    dialog.remove();
  });
  container.append(status, message, variantsList, closeButton);
  dialog.append(container);
  document.body.append(dialog);
  dialog.showModal();

  return {
    update(phase, nextMessage, variants = []) {
      const labels: Record<SyncPhase, string> = {
        publishing: "Publication Sanity en cours",
        syncing: "Synchronisation Medusa en cours",
        success: "Synchronisation Medusa reussie",
        failed: "Synchronisation Medusa echouee",
      };
      status.textContent = labels[phase];
      status.style.color = phase === "success" ? "#67d9a0" : phase === "failed" ? "#ff8a80" : "#b9b9ff";
      message.textContent = nextMessage;
      variantsList.replaceChildren();

      if (phase === "success") {
        for (const [index, variant] of variants.entries()) {
          const row = document.createElement("div");
          const title = document.createElement("span");
          const price = document.createElement("strong");
          Object.assign(row.style, {
            display: "flex",
            justifyContent: "space-between",
            gap: "16px",
            borderTop: "1px solid #353842",
            paddingTop: "8px",
          });
          title.textContent = variant.title || `Variante ${index + 1}`;
          price.textContent = formatPrice(variant.amount, variant.currency_code);
          row.append(title, price);
          variantsList.append(row);
        }
      }

      closeButton.disabled = phase === "publishing" || phase === "syncing";
      closeButton.style.opacity = closeButton.disabled ? "0.5" : "1";
    },
  };
}

export function createProductPublishAction(originalPublishAction: DocumentActionComponent): DocumentActionComponent {
  return function ProductPublishAction(props) {
    const client = useClient({apiVersion: API_VERSION});
    const originalResult = originalPublishAction(props);

    if (!originalResult) return null;

    const documentId = props.id.replace(/^drafts\./, "");
    const previousRevision = props.published?._rev;

    return {
      ...originalResult,
      onHandle: () => {
        const popup = createSyncPopup();
        popup.update("publishing", "Enregistrement de la nouvelle revision dans Sanity.");
        originalResult.onHandle?.();

        void (async () => {
          try {
            const revision = await waitForPublishedRevision(client, documentId, previousRevision);
            popup.update("syncing", "Sanity est publie. Verification de la copie dans Medusa.");
            const result = await waitForMedusaSync(documentId, revision);
            const variantCount = result.variantCount || 0;
            popup.update(
              "success",
              `${variantCount} variante(s) synchronisee(s) dans Medusa avec leurs prix.`,
              result.variants || [],
            );
          } catch (error) {
            popup.update(
              "failed",
              error instanceof Error ? error.message : "La synchronisation Medusa a echoue.",
            );
          }
        })();
      },
    };
  };
}
