"use client";

import { useCallback, useEffect, useRef, useState, type CSSProperties, type PointerEvent as EventoDePonteiro } from "react";
import { createPortal } from "react-dom";
import { ArrowsDownUp, CaretLeft, CornersOut, PictureInPicture, Resize, Rows, X } from "@phosphor-icons/react";

/*
 * Comprar sem sair da live (liveshop).
 *
 * O "Comprar" de um produto da própria loja não abre outra aba: a sala vira
 * uma janelinha (a MESMA sala, só muda de forma — nada é montado de novo, a
 * conexão e o som seguem) e por trás abre a página do produto, num quadro da
 * própria loja (`?na_live=1`). Ali a pessoa escolhe, põe no carrinho e paga.
 * Tocar na janelinha devolve a live inteira; a loja fica guardada por trás
 * para "Continuar comprando".
 *
 * A janelinha: arrasta e encaixa no canto mais perto, tem três tamanhos (no
 * computador também puxa pela borda), vira faixa no topo ou no rodapé com a
 * largura da tela, e pode ir para a janela do celular (picture in picture)
 * para seguir vendo ao sair para o app do banco. A posição fica guardada na
 * visita (sessionStorage).
 */

type Canto = "sup-esq" | "sup-dir" | "inf-esq" | "inf-dir";
type Faixa = "topo" | "rodape" | null;
type Arrumacao = { canto: Canto; largura: number | null; tamanho: 0 | 1 | 2; faixa: Faixa };

const CHAVE = "ks-live-janelinha";
const MARGEM = 12;
/* A barra da loja por trás (Voltar para a live). */
const BARRA_DA_LOJA = 44;
const LARGURAS = { celular: [168, 220, 300], computador: [280, 380, 540] } as const;

function lerArrumacao(): Arrumacao {
  const padrao: Arrumacao = { canto: "sup-dir", largura: null, tamanho: 1, faixa: null };
  try {
    const bruto = JSON.parse(sessionStorage.getItem(CHAVE) || "null") as Partial<Arrumacao> | null;
    if (!bruto) return padrao;
    return {
      canto: bruto.canto === "sup-esq" || bruto.canto === "inf-esq" || bruto.canto === "inf-dir" ? bruto.canto : "sup-dir",
      largura: typeof bruto.largura === "number" && bruto.largura > 0 ? bruto.largura : null,
      tamanho: bruto.tamanho === 0 || bruto.tamanho === 2 ? bruto.tamanho : 1,
      faixa: bruto.faixa === "topo" || bruto.faixa === "rodape" ? bruto.faixa : null,
    };
  } catch {
    return padrao;
  }
}

function guardarArrumacao(valor: Arrumacao) {
  try {
    sessionStorage.setItem(CHAVE, JSON.stringify(valor));
  } catch {
    /* sem memória da visita: só vale agora */
  }
}

/* O destino é uma página desta mesma loja? Então abre por trás da live. */
export function enderecoNaLive(destino: string | null): string | null {
  if (!destino || typeof window === "undefined") return null;
  try {
    const url = new URL(destino, window.location.origin);
    if (url.origin !== window.location.origin) return null;
    url.searchParams.set("na_live", "1");
    return `${url.pathname}${url.search}${url.hash}`;
  } catch {
    return null;
  }
}

function useTela() {
  const [tela, setTela] = useState(() => ({ l: typeof window === "undefined" ? 1280 : window.innerWidth, a: typeof window === "undefined" ? 800 : window.innerHeight }));
  useEffect(() => {
    const medir = () => setTela({ l: window.innerWidth, a: window.innerHeight });
    window.addEventListener("resize", medir);
    return () => window.removeEventListener("resize", medir);
  }, []);
  return tela;
}

/* Segura o dedo/mouse no elemento durante o arrasto (alguns aparelhos recusam: segue sem). */
function prender(elemento: Element, ponteiro: number) {
  try {
    elemento.setPointerCapture(ponteiro);
  } catch {
    /* sem captura: o arrasto ainda funciona enquanto o dedo estiver em cima */
  }
}

/* O vídeo maior que está tocando no palco: é ele que vai para a janela do celular. */
function videoDoPalco(raiz: HTMLElement | null): HTMLVideoElement | null {
  if (!raiz) return null;
  let melhor: HTMLVideoElement | null = null;
  let area = 0;
  raiz.querySelectorAll("video").forEach((video) => {
    const caixa = video.getBoundingClientRect();
    const tamanho = caixa.width * caixa.height;
    if (video.readyState > 0 && tamanho > area) {
      melhor = video;
      area = tamanho;
    }
  });
  return melhor;
}

export function useLojaNaLive(salaRef: React.RefObject<HTMLDivElement | null>) {
  const [loja, setLoja] = useState<string | null>(null);
  const [minimizada, setMinimizada] = useState(false);
  const [arrumacao, setArrumacao] = useState<Arrumacao>(() => (typeof window === "undefined" ? { canto: "sup-dir", largura: null, tamanho: 1, faixa: null } : lerArrumacao()));
  const [arrasto, setArrasto] = useState<{ x: number; y: number } | null>(null);
  const tela = useTela();
  const celular = tela.l < 760;
  const pipSozinho = useRef(false);

  const mudar = useCallback((parcial: Partial<Arrumacao>) => {
    setArrumacao((atual) => {
      const proxima = { ...atual, ...parcial };
      guardarArrumacao(proxima);
      return proxima;
    });
  }, []);

  const abrirLoja = useCallback((endereco: string) => {
    if (document.fullscreenElement) void document.exitFullscreen().catch(() => undefined);
    setLoja(endereco);
    setMinimizada(true);
  }, []);

  const expandir = useCallback(() => {
    setMinimizada(false);
    if (document.pictureInPictureElement) void document.exitPictureInPicture().catch(() => undefined);
  }, []);

  const fecharLoja = useCallback(() => {
    setLoja(null);
    setMinimizada(false);
    if (document.pictureInPictureElement) void document.exitPictureInPicture().catch(() => undefined);
  }, []);

  const janelaDoCelular = useCallback(async () => {
    const video = videoDoPalco(salaRef.current);
    if (!video || !document.pictureInPictureEnabled) return false;
    try {
      await video.requestPictureInPicture();
      return true;
    } catch {
      return false;
    }
  }, [salaRef]);

  /* Saiu para o app do banco com a live minimizada: tenta a janela do celular
     (o Safari do iPhone aceita sozinho; outros só com o botão). Voltou: fecha. */
  useEffect(() => {
    if (!minimizada) return;
    const video = videoDoPalco(salaRef.current);
    video?.setAttribute("autopictureinpicture", "");
    const aoMudar = () => {
      if (document.visibilityState === "hidden") {
        if (!document.pictureInPictureElement) {
          void janelaDoCelular().then((ok) => {
            pipSozinho.current = ok;
          });
        }
      } else if (pipSozinho.current && document.pictureInPictureElement) {
        pipSozinho.current = false;
        void document.exitPictureInPicture().catch(() => undefined);
      }
    };
    document.addEventListener("visibilitychange", aoMudar);
    return () => {
      document.removeEventListener("visibilitychange", aoMudar);
      video?.removeAttribute("autopictureinpicture");
    };
  }, [minimizada, janelaDoCelular, salaRef]);

  /* ----------------------------------------------------- onde a janelinha fica */
  const larguraMaxima = Math.max(160, tela.l - MARGEM * 2);
  const larguraDoTamanho = (celular ? LARGURAS.celular : LARGURAS.computador)[arrumacao.tamanho];
  const largura = Math.min(larguraMaxima, Math.max(160, arrumacao.largura ?? larguraDoTamanho));
  const altura = Math.round((largura * 9) / 16);
  const alturaDaFaixa = Math.round(Math.min((tela.l * 9) / 16, tela.a * 0.42));

  let estilo: CSSProperties;
  if (arrumacao.faixa) {
    estilo = { left: 0, width: tela.l, height: alturaDaFaixa, ...(arrumacao.faixa === "topo" ? { top: 0 } : { top: tela.a - alturaDaFaixa }) };
  } else if (arrasto) {
    estilo = { left: arrasto.x, top: arrasto.y, width: largura, height: altura };
  } else {
    const esquerda = arrumacao.canto.endsWith("esq");
    const emCima = arrumacao.canto.startsWith("sup");
    estilo = {
      width: largura,
      height: altura,
      left: esquerda ? MARGEM : tela.l - largura - MARGEM,
      top: emCima ? BARRA_DA_LOJA + MARGEM : tela.a - altura - MARGEM,
    };
  }

  /* A loja por trás perde a faixa ocupada pela live (quando é faixa). */
  const espacoDaLoja: CSSProperties =
    arrumacao.faixa === "topo" ? { top: alturaDaFaixa } : arrumacao.faixa === "rodape" ? { bottom: alturaDaFaixa } : {};

  /* --------------------------------------------------------- arrastar / tocar */
  const gesto = useRef<{ x0: number; y0: number; left: number; top: number; moveu: boolean } | null>(null);

  const aoApertar = (evento: EventoDePonteiro<HTMLDivElement>) => {
    if (arrumacao.faixa || (evento.target as HTMLElement).closest("button")) return;
    const caixa = evento.currentTarget.getBoundingClientRect();
    gesto.current = { x0: evento.clientX, y0: evento.clientY, left: caixa.left, top: caixa.top, moveu: false };
    prender(evento.currentTarget, evento.pointerId);
  };
  const aoMover = (evento: EventoDePonteiro<HTMLDivElement>) => {
    const g = gesto.current;
    if (!g) return;
    const dx = evento.clientX - g.x0;
    const dy = evento.clientY - g.y0;
    if (!g.moveu && Math.hypot(dx, dy) < 6) return;
    g.moveu = true;
    setArrasto({
      x: Math.min(tela.l - largura, Math.max(0, g.left + dx)),
      y: Math.min(tela.a - altura, Math.max(0, g.top + dy)),
    });
  };
  const aoSoltar = (evento: EventoDePonteiro<HTMLDivElement>) => {
    const g = gesto.current;
    gesto.current = null;
    if (!g) return;
    if (!g.moveu) {
      expandir();
      return;
    }
    /* Encaixa no canto mais perto do meio da janelinha. */
    const meioX = Math.min(tela.l - largura, Math.max(0, g.left + evento.clientX - g.x0)) + largura / 2;
    const meioY = Math.min(tela.a - altura, Math.max(0, g.top + evento.clientY - g.y0)) + altura / 2;
    const canto: Canto = `${meioY < tela.a / 2 ? "sup" : "inf"}-${meioX < tela.l / 2 ? "esq" : "dir"}`;
    setArrasto(null);
    mudar({ canto });
  };

  /* Puxar pela borda (computador): a alça fica no canto de dentro. */
  const puxada = useRef<{ x0: number; largura: number; sinal: 1 | -1 } | null>(null);
  const aoApertarAlca = (evento: EventoDePonteiro<HTMLSpanElement>) => {
    evento.stopPropagation();
    puxada.current = { x0: evento.clientX, largura, sinal: arrumacao.canto.endsWith("dir") ? -1 : 1 };
    prender(evento.currentTarget, evento.pointerId);
  };
  const aoMoverAlca = (evento: EventoDePonteiro<HTMLSpanElement>) => {
    const p = puxada.current;
    if (!p) return;
    mudar({ largura: Math.min(larguraMaxima, Math.max(200, p.largura + (evento.clientX - p.x0) * p.sinal)) });
  };
  const aoSoltarAlca = () => {
    puxada.current = null;
  };

  const proximoTamanho = () => mudar({ tamanho: ((arrumacao.tamanho + 1) % 3) as 0 | 1 | 2, largura: null });
  const alternarFaixa = () => mudar({ faixa: arrumacao.faixa ? null : celular ? "topo" : "rodape" });
  const trocarFaixa = () => mudar({ faixa: arrumacao.faixa === "topo" ? "rodape" : "topo" });

  const controles = minimizada ? (
    <div className="lv-mini-camada" onPointerDown={aoApertar} onPointerMove={aoMover} onPointerUp={aoSoltar} onPointerCancel={() => { gesto.current = null; setArrasto(null); }}>
      <span className="lv-mini-vivo">Ao vivo</span>
      <div className="lv-mini-botoes">
        {!arrumacao.faixa ? (
          <button type="button" onClick={proximoTamanho} aria-label="Mudar o tamanho" title="Mudar o tamanho">
            <Resize />
          </button>
        ) : (
          <button type="button" onClick={trocarFaixa} aria-label={arrumacao.faixa === "topo" ? "Levar a faixa para baixo" : "Levar a faixa para cima"} title="Trocar topo e rodapé">
            <ArrowsDownUp />
          </button>
        )}
        <button type="button" onClick={alternarFaixa} aria-label={arrumacao.faixa ? "Voltar a janelinha" : "Faixa na largura da tela"} title={arrumacao.faixa ? "Voltar a janelinha" : "Faixa na largura da tela"} className={arrumacao.faixa ? "on" : ""}>
          <Rows />
        </button>
        {typeof document !== "undefined" && document.pictureInPictureEnabled ? (
          <button type="button" onClick={() => void janelaDoCelular()} aria-label="Janela do celular, por cima de outros apps" title="Ver por cima de outros apps">
            <PictureInPicture />
          </button>
        ) : null}
        <button type="button" onClick={expandir} aria-label="Voltar para a live" title="Voltar para a live">
          <CornersOut />
        </button>
      </div>
      {!arrumacao.faixa && !celular ? (
        <span
          className={`lv-mini-alca ${arrumacao.canto.startsWith("sup") ? "baixo" : "cima"} ${arrumacao.canto.endsWith("dir") ? "esq" : "dir"}`}
          onPointerDown={aoApertarAlca}
          onPointerMove={aoMoverAlca}
          onPointerUp={aoSoltarAlca}
          aria-hidden
        />
      ) : null}
    </div>
  ) : null;

  return { loja, minimizada, abrirLoja, expandir, fecharLoja, estiloDaJanela: minimizada ? estilo : undefined, controles, espacoDaLoja, arrastando: Boolean(arrasto) };
}

/* A loja por trás da live minimizada. Fica montada (escondida) enquanto a live
   está grande, para o "Continuar comprando" voltar onde a pessoa parou. */
export function LojaPorTras({
  endereco,
  visivel,
  espaco,
  nomeDaLoja,
  aoVoltar,
  aoFechar,
}: {
  endereco: string;
  visivel: boolean;
  espaco: CSSProperties;
  nomeDaLoja: string;
  aoVoltar: () => void;
  aoFechar: () => void;
}) {
  const [montado, setMontado] = useState(false);
  useEffect(() => setMontado(true), []);
  if (!montado) return null;
  return createPortal(
    <div className="lv-loja" style={{ ...espaco, display: visivel ? "flex" : "none" }} aria-hidden={!visivel}>
      <div className="lv-loja-barra">
        <button type="button" onClick={aoVoltar}>
          <CaretLeft /> Voltar para a live
        </button>
        <span>{nomeDaLoja}</span>
        <button type="button" onClick={aoFechar} aria-label="Fechar a loja e voltar para a live">
          <X />
        </button>
      </div>
      <iframe src={endereco} title={`Loja ${nomeDaLoja}`} allow="clipboard-write; payment; fullscreen; autoplay" />
    </div>,
    document.body
  );
}
