"use client";

/* eslint-disable @next/next/no-img-element */
import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Maximize2, Play, Volume2, VolumeX, X } from "lucide-react";

import {
  avisarQueTocou,
  comandarPlayer,
  enderecoIncorporado,
  EVENTO_DO_VIDEO,
  type OrigemDoVideo,
  type VideoDoProduto,
} from "@/lib/video-do-produto";
import { estaDentroDaLive } from "@/lib/live/dentro-da-live";

/*
 * O vídeo do produto na loja (migration 183), como na Shopee:
 * - PlayerDaGaleria: o primeiro item da galeria (capa com o play, ou já
 *   tocando se a loja ligou "começar sozinho").
 * - VideoFlutuante: a janelinha no canto que já abre rodando. Tocar no meio
 *   pausa e continua; o alto-falante liga e desliga o som; o botão de
 *   expandir abre em tela cheia; o X fecha (e não volta nesta visita).
 * Um vídeo por vez: dar play num pausa o outro (avisarQueTocou).
 * Como tocam (som, repetir, controles) vem de video.opcoes (migration 184).
 *
 * Os dois só cuidam do vídeo: a moldura (cantos, bordas) é de cada tema.
 */

/*
 * Toca um <video> do jeito pedido. Se a loja quer com som e o navegador
 * bloqueia (o cliente ainda não tocou na página), começa mudo e avisa:
 * `bloqueado` liga o "Toque para ouvir".
 */
function useTocarArquivo(ativo: boolean, mudo: boolean) {
  const elemento = useRef<HTMLVideoElement | null>(null);
  const [bloqueado, setBloqueado] = useState(false);

  useEffect(() => {
    const atual = elemento.current;
    if (!atual) return;
    if (!ativo) {
      atual.pause();
      return;
    }
    atual.muted = mudo;
    atual.play().catch(() => {
      if (mudo) return;
      atual.muted = true;
      setBloqueado(true);
      void atual.play().catch(() => undefined);
    });
  }, [ativo, mudo]);

  const ouvir = useCallback(() => {
    const atual = elemento.current;
    if (!atual) return;
    atual.muted = false;
    setBloqueado(false);
    void atual.play().catch(() => undefined);
  }, []);

  return { elemento, bloqueado, ouvir };
}

/* A página está dentro da live (a loja por trás da live minimizada): o som é
   da live, então o vídeo do produto não começa sozinho nem flutua. */
function dentroDaLive() {
  return estaDentroDaLive();
}

/* Escuta o outro vídeo do produto começar a tocar. */
function useQuandoOOutroTocar(eu: OrigemDoVideo, aoTocar: () => void) {
  const callback = useRef(aoTocar);
  callback.current = aoTocar;
  useEffect(() => {
    const ouvir = (evento: Event) => {
      if ((evento as CustomEvent<OrigemDoVideo>).detail !== eu) callback.current();
    };
    window.addEventListener(EVENTO_DO_VIDEO, ouvir);
    return () => window.removeEventListener(EVENTO_DO_VIDEO, ouvir);
  }, [eu]);
}

function ToqueParaOuvir({ aoTocar }: { aoTocar: () => void }) {
  return (
    <button
      type="button"
      onClick={(e) => {
        e.stopPropagation();
        aoTocar();
      }}
      className="absolute left-1/2 top-3 z-[2] inline-flex -translate-x-1/2 items-center gap-1.5 whitespace-nowrap rounded-full bg-black/70 px-3 py-1.5 text-[12px] font-semibold text-white shadow-lg backdrop-blur-sm"
    >
      <VolumeX size={14} /> Toque para ouvir
    </button>
  );
}

export function PlayerDaGaleria({
  video,
  capa,
  nome,
  sozinho = false,
}: {
  video: VideoDoProduto;
  capa: string | null;
  nome: string;
  /* Começa sem esperar o play (a loja ligou e não há janelinha rodando). */
  sozinho?: boolean;
}) {
  const opcoes = video.opcoes.galeria;
  const [tocando, setTocando] = useState(sozinho);
  /* Tocar no play é um toque na página: aí o som sempre vale. */
  const [peloPlay, setPeloPlay] = useState(false);
  const peloPlayRef = useRef(false);
  peloPlayRef.current = peloPlay;
  const mudo = peloPlay ? false : !opcoes.comSom;
  const { elemento, bloqueado, ouvir } = useTocarArquivo(tocando && video.tipo === "arquivo", mudo);
  const quadro = useRef<HTMLIFrameElement | null>(null);

  /* A janelinha começou a tocar: a galeria pausa. */
  useQuandoOOutroTocar("galeria", () => {
    elemento.current?.pause();
    if (video.tipo === "link") comandarPlayer(quadro.current, video.link.provedor, "pausar");
  });

  /* Dentro da live, a galeria espera o play (o som é da live). */
  useEffect(() => {
    if (sozinho && dentroDaLive()) setTocando((agora) => (peloPlayRef.current ? agora : false));
  }, [sozinho]);

  /* Link: não dá para ouvir o "play" de dentro do player; quem tocou foi a galeria. */
  useEffect(() => {
    if (tocando && video.tipo === "link") avisarQueTocou("galeria");
  }, [tocando, video.tipo]);

  if (tocando) {
    return video.tipo === "arquivo" ? (
      <div className="relative h-full w-full bg-black">
        <video
          ref={elemento}
          src={video.endereco}
          poster={capa ?? undefined}
          className="h-full w-full object-contain"
          controls={opcoes.controles}
          loop={opcoes.repetir}
          muted={mudo}
          playsInline
          onPlay={() => avisarQueTocou("galeria")}
          onClick={opcoes.controles ? undefined : (e) => (e.currentTarget.paused ? void e.currentTarget.play() : e.currentTarget.pause())}
        />
        {bloqueado ? <ToqueParaOuvir aoTocar={ouvir} /> : null}
      </div>
    ) : (
      <iframe
        ref={quadro}
        src={enderecoIncorporado(video.link, { sozinho: true, mudo, repetir: opcoes.repetir, controles: opcoes.controles })}
        title={`Vídeo de ${nome}`}
        className="h-full w-full bg-black"
        allow="autoplay; encrypted-media; picture-in-picture; fullscreen"
        allowFullScreen
      />
    );
  }

  return (
    <button
      type="button"
      onClick={() => {
        setPeloPlay(true);
        setTocando(true);
      }}
      className="group/video relative block h-full w-full bg-black"
      aria-label={`Assistir o vídeo de ${nome}`}
    >
      {capa ? <img src={capa} alt="" className="h-full w-full object-cover opacity-90" /> : null}
      <span className="absolute inset-0 flex items-center justify-center">
        <span className="flex h-16 w-16 items-center justify-center rounded-full bg-black/55 text-white shadow-lg backdrop-blur-sm transition-transform group-hover/video:scale-110">
          <Play size={28} fill="currentColor" className="ml-1" />
        </span>
      </span>
    </button>
  );
}

/* O selo de play por cima da miniatura do vídeo na fileira da galeria. */
export function SeloDePlay() {
  return (
    <span className="pointer-events-none absolute inset-0 flex items-center justify-center bg-black/25">
      <span className="flex h-7 w-7 items-center justify-center rounded-full bg-black/60 text-white">
        <Play size={13} fill="currentColor" className="ml-0.5" />
      </span>
    </span>
  );
}

const CHAVE_FECHADO = "ks-video-flutuante-fechado";

export function VideoFlutuante({
  video,
  produtoId,
  nome,
  capa,
  rodapeNoCelular = 96,
  rodapeNoComputador = 92,
}: {
  video: VideoDoProduto;
  produtoId: string;
  nome: string;
  capa: string | null;
  /* Quanto subir no celular para não cobrir a barra de compra do tema. */
  rodapeNoCelular?: number;
  /* E no computador, para ficar acima do botão de conversa (que sobe junto com a barra de compra). */
  rodapeNoComputador?: number;
}) {
  const [fechado, setFechado] = useState(true);
  const [aberto, setAberto] = useState(false);
  const [pausado, setPausado] = useState(false);
  const [deitado, setDeitado] = useState(video.tipo === "link");
  const [montado, setMontado] = useState(false);
  const opcoes = video.opcoes.flutuante;
  const [semSom, setSemSom] = useState(!opcoes.comSom);
  const ativo = montado && !fechado && !aberto && !pausado;
  /* `semSom` é a escolha do cliente: continuar depois de pausar não muda o som. */
  const { elemento, bloqueado } = useTocarArquivo(ativo && video.tipo === "arquivo", semSom);
  const quadro = useRef<HTMLIFrameElement | null>(null);

  /* Fechou nesta visita, não volta (sessionStorage pode faltar: aí mostra).
     Dentro da live a janelinha não aparece. */
  useEffect(() => {
    if (dentroDaLive()) return;
    setMontado(true);
    try {
      setFechado(sessionStorage.getItem(`${CHAVE_FECHADO}:${produtoId}`) === "1");
    } catch {
      setFechado(false);
    }
  }, [produtoId]);

  /* O navegador bloqueou o som: o alto-falante mostra mudo. */
  useEffect(() => {
    if (bloqueado) setSemSom(true);
  }, [bloqueado]);

  /* Link: pausar e continuar pelo player de dentro (a janelinha não tem controles). */
  useEffect(() => {
    if (video.tipo !== "link" || !montado || fechado) return;
    comandarPlayer(quadro.current, video.link.provedor, ativo ? "tocar" : "pausar");
  }, [ativo, video, montado, fechado]);

  /* O vídeo da galeria começou a tocar: a janelinha pausa. */
  useQuandoOOutroTocar("flutuante", () => setPausado(true));

  const fechar = useCallback(() => {
    setFechado(true);
    try {
      sessionStorage.setItem(`${CHAVE_FECHADO}:${produtoId}`, "1");
    } catch {
      /* sem memória da visita: só some agora */
    }
  }, [produtoId]);

  const alternarPausa = useCallback(() => {
    setPausado((agora) => {
      if (agora) avisarQueTocou("flutuante");
      return !agora;
    });
  }, []);

  const alternarSom = useCallback(() => {
    const proximo = !semSom;
    setSemSom(proximo);
    if (video.tipo === "arquivo") {
      const atual = elemento.current;
      if (atual) {
        atual.muted = proximo;
        if (!proximo && atual.paused) void atual.play().catch(() => undefined);
      }
    } else {
      comandarPlayer(quadro.current, video.link.provedor, proximo ? "mudo" : "som");
    }
    if (!proximo) {
      setPausado(false);
      avisarQueTocou("flutuante");
    }
  }, [elemento, semSom, video]);

  useEffect(() => {
    if (!aberto) return;
    const aoTeclar = (evento: KeyboardEvent) => {
      if (evento.key === "Escape") setAberto(false);
    };
    window.addEventListener("keydown", aoTeclar);
    const rolagem = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", aoTeclar);
      document.body.style.overflow = rolagem;
    };
  }, [aberto]);

  if (!montado) return null;

  /* No celular fica à esquerda, acima da barra de compra; no computador, à
     direita, acima do botão de conversa (à esquerda cobria a galeria). */
  const largura = deitado ? "w-[200px] sm:w-[240px]" : "w-[112px] sm:w-[148px]";
  const proporcao = deitado ? "16 / 9" : "9 / 16";
  const botaoDoCanto = "absolute flex h-7 w-7 items-center justify-center rounded-full bg-black/60 text-white hover:bg-black/80";

  return createPortal(
    <>
      {!fechado ? (
        <div
          className={`ks-video-flutuante fixed left-4 z-[60] lg:left-auto lg:right-6 overflow-hidden rounded-2xl bg-black shadow-[0_12px_36px_rgba(0,0,0,0.35)] ring-1 ring-white/20 ${largura}`}
          style={{
            aspectRatio: proporcao,
            bottom: `calc(env(safe-area-inset-bottom, 0px) + var(--ks-video-flutuante-base, ${rodapeNoCelular}px))`,
            ["--ks-video-flutuante-computador" as string]: `${rodapeNoComputador}px`,
          }}
        >
          <style>{`@media (min-width: 1024px) { .ks-video-flutuante { --ks-video-flutuante-base: var(--ks-video-flutuante-computador); } }`}</style>
          {video.tipo === "arquivo" ? (
            <video
              ref={elemento}
              src={video.endereco}
              poster={capa ?? undefined}
              className="h-full w-full object-cover"
              muted={!opcoes.comSom}
              loop={opcoes.repetir}
              playsInline
              preload="metadata"
              onLoadedMetadata={(e) => setDeitado(e.currentTarget.videoWidth > e.currentTarget.videoHeight)}
              onVolumeChange={(e) => setSemSom(e.currentTarget.muted)}
              onEnded={() => setPausado(true)}
            />
          ) : (
            <iframe
              ref={quadro}
              src={enderecoIncorporado(video.link, { sozinho: true, mudo: !opcoes.comSom, repetir: opcoes.repetir, controles: false })}
              title={`Vídeo de ${nome}`}
              className="pointer-events-none h-full w-full"
              allow="autoplay; encrypted-media"
              tabIndex={-1}
            />
          )}

          {/* O meio da janelinha pausa e continua. */}
          <button type="button" onClick={alternarPausa} className="absolute inset-0" aria-label={pausado ? "Continuar o vídeo" : "Pausar o vídeo"}>
            {pausado ? (
              <span className="absolute left-1/2 top-1/2 flex h-11 w-11 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-black/60 text-white">
                <Play size={20} fill="currentColor" className="ml-0.5" />
              </span>
            ) : null}
          </button>

          <button type="button" onClick={alternarSom} className={`${botaoDoCanto} bottom-2 left-2 ${bloqueado && semSom ? "animate-pulse" : ""}`} aria-label={semSom ? "Ligar o som" : "Tirar o som"}>
            {semSom ? <VolumeX size={14} /> : <Volume2 size={14} />}
          </button>
          <button type="button" onClick={() => setAberto(true)} className={`${botaoDoCanto} bottom-2 right-2`} aria-label={`Assistir o vídeo de ${nome} em tela cheia`}>
            <Maximize2 size={13} />
          </button>
          <button type="button" onClick={fechar} className={`${botaoDoCanto} right-1.5 top-1.5`} aria-label="Fechar o vídeo">
            <X size={14} />
          </button>
        </div>
      ) : null}

      {aberto ? (
        <div role="dialog" aria-modal="true" aria-label={`Vídeo de ${nome}`} onClick={() => setAberto(false)} className="fixed inset-0 z-[120] flex items-center justify-center bg-black/85 p-4">
          <button type="button" onClick={() => setAberto(false)} className="absolute right-4 top-4 flex h-10 w-10 items-center justify-center rounded-full bg-white/15 text-white hover:bg-white/25" aria-label="Fechar">
            <X size={20} />
          </button>
          <div onClick={(e) => e.stopPropagation()} className={deitado ? "aspect-video w-full max-w-4xl" : "aspect-[9/16] h-[min(86vh,820px)]"}>
            {video.tipo === "arquivo" ? (
              <video
                src={video.endereco}
                poster={capa ?? undefined}
                className="h-full w-full rounded-xl bg-black object-contain"
                controls
                autoPlay
                playsInline
                onPlay={() => avisarQueTocou("flutuante")}
              />
            ) : (
              <iframe
                src={enderecoIncorporado(video.link, { sozinho: true, mudo: false, repetir: false, controles: true })}
                title={`Vídeo de ${nome}`}
                className="h-full w-full rounded-xl bg-black"
                allow="autoplay; encrypted-media; picture-in-picture; fullscreen"
                allowFullScreen
              />
            )}
          </div>
        </div>
      ) : null}
    </>,
    document.body
  );
}
