"use client";

import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { ArrowDown, ArrowUp, Copy, EyeOff, Pencil, Plus, Trash2 } from "lucide-react";
import {
  CANAL_DO_EDITOR,
  lerMensagemDoPainel,
  modoDaSecao,
  type AcaoDaLoja,
  type MensagemDaLoja,
  type SecaoDaPagina,
  type SecaoDoRascunho,
} from "@/lib/pagina-inicial";
import { ContextoNoEditor } from "./contexto";

/*
  O editor da página inicial, do lado da loja.

  A página roda dentro de um quadro do painel (Catálogo > Produtos > Página
  inicial). Aqui ela:

  - avisa o painel que está pronta (e, no Vendor que nunca publicou, manda a
    home automática escrita como seções, para o rascunho começar igual);
  - recebe o rascunho a cada mudança e desenha as seções dele;
  - põe em volta de cada seção o contorno, o nome e os botões (subir, descer,
    editar, duplicar, esconder, apagar) e o "+" entre elas. Os botões não
    mudam nada aqui: só contam ao painel, que muda o rascunho e manda de volta;
  - segura os links (o lojista está montando a página, não navegando).

  Conversa só com a origem do painel que veio assinada na passagem (e só com
  a janela que contém este quadro). Mensagem de qualquer outro lugar é
  ignorada.
*/

const NOMES: Record<string, string> = {
  manual_products: "Produtos escolhidos",
  all_products: "Todos os produtos",
  category_products: "Produtos de uma categoria",
  subcategory_products: "Produtos de uma subcategoria",
  image_banner: "Banner",
  category_navigator: "Atalhos de categorias",
  image_grid: "Imagens lado a lado",
  banner_carousel: "Carrossel de banners",
  featured_products: "Primeiros produtos",
  category_circles: "Categorias em círculos",
};

export function rotuloDaSecao(secao: { title?: string | null; config?: unknown; section_type?: unknown }, rotulo?: string) {
  const tipo = rotulo || NOMES[modoDaSecao(secao)] || "Seção";
  const titulo = String(secao.title || "").trim();
  return titulo && titulo !== tipo ? `${tipo} · ${titulo}` : tipo;
}

type Estado = {
  selecionada: string | null;
  /* 1 / escala da loja no painel: os botões crescem o que a loja encolheu. */
  zoom: number;
  enviarAcao: (acao: AcaoDaLoja, id: string | null, indice?: number) => void;
  rotulos: Map<string, string>;
  total: number;
};

const ContextoDoEditor = createContext<Estado | null>(null);

function noQuadro() {
  try {
    return window.self !== window.top;
  } catch {
    return true;
  }
}

/**
 * A conversa com o painel. Devolve o rascunho (null até o painel mandar o
 * primeiro) e o provedor que as molduras usam.
 */
export function useConversaComOPainel({
  origemDoPainel,
  tema,
  homeEditada,
  arranjoAutomatico,
}: {
  origemDoPainel: string;
  tema: string;
  homeEditada: boolean;
  arranjoAutomatico: SecaoDaPagina[] | null;
}) {
  const [rascunho, setRascunho] = useState<SecaoDoRascunho[] | null>(null);
  const [selecionada, setSelecionada] = useState<string | null>(null);
  const [foraDoPainel, setForaDoPainel] = useState(false);
  const [zoom, setZoom] = useState(1);
  const arranjo = useRef(arranjoAutomatico);
  const ouviuOPainel = useRef(false);

  const enviar = useCallback(
    (mensagem: MensagemDaLoja) => {
      if (typeof window === "undefined" || window.parent === window) return;
      window.parent.postMessage(mensagem, origemDoPainel);
    },
    [origemDoPainel]
  );

  useEffect(() => {
    if (!noQuadro()) {
      setForaDoPainel(true);
      return;
    }

    const aoReceber = (evento: MessageEvent) => {
      if (evento.origin !== origemDoPainel || evento.source !== window.parent) return;
      const mensagem = lerMensagemDoPainel(evento.data);
      if (!mensagem) return;
      ouviuOPainel.current = true;
      if (mensagem.tipo === "rascunho") {
        setRascunho(mensagem.secoes);
        setSelecionada(mensagem.selecionada);
      } else if (mensagem.tipo === "selecionar") {
        setSelecionada(mensagem.id);
      } else if (mensagem.tipo === "escala") {
        setZoom(Math.min(2.2, 1 / mensagem.valor));
      } else if (mensagem.tipo === "rolar") {
        /* Espera o rascunho novo ser desenhado antes de rolar até ele. */
        window.setTimeout(() => {
          const alvo = document.querySelector(`[data-ks-secao="${CSS.escape(mensagem.id)}"]`);
          alvo?.scrollIntoView({ behavior: "smooth", block: "center" });
        }, 120);
      }
    };
    window.addEventListener("message", aoReceber);

    /* Os links ficam parados: o lojista está montando, não navegando. */
    const aoClicar = (evento: MouseEvent) => {
      const alvo = evento.target as Element | null;
      if (!alvo || alvo.closest("[data-ks-editor-ui]")) return;
      const link = alvo.closest("a[href]");
      if (!link) return;
      evento.preventDefault();
      enviar({ canal: CANAL_DO_EDITOR, tipo: "link-bloqueado" });
    };
    const aoEnviar = (evento: Event) => evento.preventDefault();
    document.addEventListener("click", aoClicar, true);
    document.addEventListener("submit", aoEnviar, true);

    enviar({ canal: CANAL_DO_EDITOR, tipo: "pronto", tema, homeEditada, arranjoAutomatico: arranjo.current });
    /* O "pronto" pode chegar antes de o painel estar ouvindo (a loja abre
       mais rápido que o painel, ou o painel recarregou): repete até o painel
       responder, por meio minuto no máximo. */
    let vezes = 0;
    const repetir = window.setInterval(() => {
      vezes += 1;
      if (ouviuOPainel.current || vezes > 15) {
        window.clearInterval(repetir);
        return;
      }
      enviar({ canal: CANAL_DO_EDITOR, tipo: "pronto", tema, homeEditada, arranjoAutomatico: arranjo.current });
    }, 2000);

    return () => {
      window.clearInterval(repetir);
      window.removeEventListener("message", aoReceber);
      document.removeEventListener("click", aoClicar, true);
      document.removeEventListener("submit", aoEnviar, true);
    };
  }, [enviar, homeEditada, origemDoPainel, tema]);

  const enviarAcao = useCallback(
    (acao: AcaoDaLoja, id: string | null, indice?: number) => {
      if (acao === "selecionar" || acao === "editar") setSelecionada(id);
      enviar({ canal: CANAL_DO_EDITOR, tipo: "acao", acao, id, ...(indice !== undefined ? { indice } : {}) });
    },
    [enviar]
  );

  const rotulos = useMemo(() => new Map((rascunho || []).map((s) => [s.id, s.rotulo])), [rascunho]);

  return { rascunho, selecionada, foraDoPainel, enviarAcao, rotulos, zoom };
}

export function ProvedorDoEditor({
  selecionada,
  enviarAcao,
  rotulos,
  total,
  zoom,
  foraDoPainel,
  children,
}: Estado & { foraDoPainel: boolean; children: ReactNode }) {
  const valor = useMemo(() => ({ selecionada, enviarAcao, rotulos, total, zoom }), [selecionada, enviarAcao, rotulos, total, zoom]);
  const noEditor = useMemo(() => ({ mostrarVazios: true as const, zoom }), [zoom]);
  return (
    <ContextoNoEditor.Provider value={noEditor}>
      <ContextoDoEditor.Provider value={valor}>
        {foraDoPainel ? (
          <div
            data-ks-editor-ui
            className="sticky top-0 z-[90] bg-[#7C3AED] px-4 py-2 text-center text-[13px] font-semibold text-white"
          >
            Esta é a visualização do editor da página inicial. Para mexer, abra pelo painel em Catálogo &gt; Produtos &gt; Página inicial.
          </div>
        ) : null}
        {children}
      </ContextoDoEditor.Provider>
    </ContextoNoEditor.Provider>
  );
}

function BotaoDaMoldura({ titulo, onClick, perigo, children }: { titulo: string; onClick: () => void; perigo?: boolean; children: ReactNode }) {
  return (
    <button
      type="button"
      title={titulo}
      aria-label={titulo}
      onClick={(e) => {
        e.preventDefault();
        e.stopPropagation();
        onClick();
      }}
      className={`flex h-8 w-8 items-center justify-center rounded-full transition ${
        perigo ? "text-rose-600 hover:bg-rose-50" : "text-slate-700 hover:bg-violet-50 hover:text-[#6D28D9]"
      }`}
    >
      {children}
    </button>
  );
}

function BotaoDeInserir({ indice, posicao }: { indice: number; posicao: "topo" | "base" }) {
  const editor = useContext(ContextoDoEditor);
  if (!editor) return null;
  return (
    <div
      data-ks-editor-ui
      className={`pointer-events-none absolute inset-x-0 z-[37] flex justify-center opacity-0 transition-opacity group-hover/ks:opacity-100 ${
        posicao === "topo" ? "-top-4" : "-bottom-4"
      }`}
    >
      <button
        type="button"
        style={{ transform: `scale(${editor.zoom})` }}
        onClick={(e) => {
          e.preventDefault();
          e.stopPropagation();
          editor.enviarAcao("inserir", null, indice);
        }}
        className="pointer-events-auto flex h-8 items-center gap-1.5 rounded-full bg-[#7C3AED] pl-2.5 pr-3.5 text-[12px] font-bold text-white shadow-[0_8px_20px_-6px_rgba(124,58,237,0.65)] transition hover:bg-[#6D28D9]"
      >
        <Plus className="h-4 w-4" strokeWidth={2.6} />
        Adicionar seção aqui
      </button>
    </div>
  );
}

/** O contorno, o nome e os botões em volta de uma seção. */
export function MolduraDaSecao({
  id,
  indice,
  rotulo,
  podeApagar = true,
  children,
}: {
  id: string;
  indice: number;
  rotulo: string;
  podeApagar?: boolean;
  children: ReactNode;
}) {
  const editor = useContext(ContextoDoEditor);
  if (!editor) return <>{children}</>;
  const escolhida = editor.selecionada === id;
  const ultima = indice >= editor.total - 1;

  return (
    <div
      data-ks-secao={id}
      className="group/ks relative"
      onClick={() => editor.enviarAcao("selecionar", id)}
      style={{ cursor: "pointer", minHeight: 24 }}
    >
      {children}
      <div
        aria-hidden
        className={`pointer-events-none absolute inset-0 z-[35] transition ${
          escolhida ? "opacity-100" : "opacity-0 group-hover/ks:opacity-100"
        }`}
        style={{
          outline: `${escolhida ? 3 : 2}px ${escolhida ? "solid" : "dashed"} #7C3AED`,
          outlineOffset: -3,
          background: escolhida ? "rgba(124,58,237,0.04)" : undefined,
        }}
      />
      <div
        data-ks-editor-ui
        style={{ transform: `scale(${editor.zoom})`, transformOrigin: "top left" }}
        className={`absolute left-2 top-2 z-[36] max-w-[55%] truncate rounded-full px-3 py-1 text-[11px] font-bold tracking-wide text-white shadow-md transition ${
          escolhida ? "bg-[#7C3AED] opacity-100" : "bg-[#7C3AED]/90 opacity-0 group-hover/ks:opacity-100"
        }`}
      >
        {rotulo}
      </div>
      <div
        data-ks-editor-ui
        style={{ transform: `scale(${editor.zoom})`, transformOrigin: "top right" }}
        className={`absolute right-2 top-2 z-[36] flex items-center gap-0.5 rounded-full border border-violet-100 bg-white/95 p-1 shadow-[0_10px_28px_-10px_rgba(15,23,42,0.45)] backdrop-blur transition ${
          escolhida ? "opacity-100" : "opacity-0 group-hover/ks:opacity-100"
        }`}
      >
        <BotaoDaMoldura titulo="Subir" onClick={() => editor.enviarAcao("subir", id)}>
          <ArrowUp className={`h-4 w-4 ${indice === 0 ? "opacity-30" : ""}`} />
        </BotaoDaMoldura>
        <BotaoDaMoldura titulo="Descer" onClick={() => editor.enviarAcao("descer", id)}>
          <ArrowDown className={`h-4 w-4 ${ultima ? "opacity-30" : ""}`} />
        </BotaoDaMoldura>
        <BotaoDaMoldura titulo="Editar" onClick={() => editor.enviarAcao("editar", id)}>
          <Pencil className="h-4 w-4" />
        </BotaoDaMoldura>
        {podeApagar ? (
          <>
            <BotaoDaMoldura titulo="Duplicar" onClick={() => editor.enviarAcao("duplicar", id)}>
              <Copy className="h-4 w-4" />
            </BotaoDaMoldura>
            <BotaoDaMoldura titulo="Esconder" onClick={() => editor.enviarAcao("ocultar", id)}>
              <EyeOff className="h-4 w-4" />
            </BotaoDaMoldura>
            <BotaoDaMoldura titulo="Apagar" perigo onClick={() => editor.enviarAcao("excluir", id)}>
              <Trash2 className="h-4 w-4" />
            </BotaoDaMoldura>
          </>
        ) : null}
      </div>
      {indice === 0 ? <BotaoDeInserir indice={0} posicao="topo" /> : null}
      <BotaoDeInserir indice={indice + 1} posicao="base" />
    </div>
  );
}

/** A página sem seção nenhuma: o lugar para pôr a primeira. */
export function PaginaVaziaNoEditor() {
  const editor = useContext(ContextoDoEditor);
  if (!editor) return null;
  return (
    <div data-ks-editor-ui className="mx-auto my-10 w-full max-w-3xl px-4">
      <button
        type="button"
        onClick={() => editor.enviarAcao("inserir", null, 0)}
        className="flex w-full flex-col items-center gap-2 rounded-3xl border-2 border-dashed border-violet-300 bg-violet-50/60 px-6 py-12 text-violet-700 transition hover:border-violet-500 hover:bg-violet-50"
      >
        <Plus className="h-7 w-7" />
        <span className="text-sm font-bold">Adicionar a primeira seção</span>
      </button>
    </div>
  );
}
