"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { FolderOpen, Link2, Loader2, Lock, Trash2, Upload, Video } from "lucide-react";

import { Switch } from "@/components/ui/switch";
import { EscolherDaBiblioteca } from "@/components/digitais/biblioteca";
import { enviarArquivo, medirVideo, type ProgressoDoEnvio } from "@/components/digitais/enviar-arquivo";
import { duracaoPassou, VIDEO_DO_PRODUTO } from "@/lib/limites-do-video-do-produto";
import { lerLinkDeVideo } from "@/lib/digitais/curso";
import { lerOpcoesDoVideo, OPCOES_PADRAO, type OpcoesDoVideo } from "@/lib/opcoes-do-video";
import { cn } from "@/lib/utils";

/*
 * O vídeo do produto (migration 183), como na Shopee e no Mercado Livre:
 * entra como o primeiro item da galeria da loja.
 *
 * - Vídeo próprio: vai para os arquivos da empresa (o mesmo lugar e o mesmo
 *   espaço dos Produtos digitais). Vale para todas as empresas com a
 *   assinatura em dia, mesmo sem Produtos digitais (rotas em modo
 *   videoDoProduto); até 1 min, 50 MB e 10 produtos.
 * - Link do YouTube (ou Vimeo): qualquer empresa.
 * - Flutuante: o vídeo abre sozinho, sem som, numa janelinha no canto da
 *   página do produto.
 */

export type VideoDoProdutoNoCadastro = {
  modo: "arquivo" | "link";
  arquivoId: string | null;
  link: string;
  flutuante: boolean;
  /* Como toca na galeria e na janelinha (migration 184). */
  opcoes: OpcoesDoVideo;
};

export const VIDEO_VAZIO: VideoDoProdutoNoCadastro = { modo: "arquivo", arquivoId: null, link: "", flutuante: false, opcoes: OPCOES_PADRAO };

/* O que vem do banco → o estado do cadastro. */
export function videoDoProdutoSalvo(produto: Record<string, unknown> | null | undefined): VideoDoProdutoNoCadastro {
  const arquivoId = typeof produto?.video_file_id === "string" ? produto.video_file_id : null;
  const bruto = produto?.video_link;
  const link = bruto && typeof bruto === "object" && typeof (bruto as { url?: unknown }).url === "string" ? String((bruto as { url: string }).url) : "";
  return {
    modo: arquivoId ? "arquivo" : link ? "link" : "arquivo",
    arquivoId,
    link: linkParaMostrar(link),
    flutuante: produto?.video_flutuante === true,
    opcoes: lerOpcoesDoVideo(produto?.video_opcoes),
  };
}

/* O estado do cadastro → o que vai para /api/products. */
export function videoParaSalvar(video: VideoDoProdutoNoCadastro) {
  const temArquivo = video.modo === "arquivo" && Boolean(video.arquivoId);
  const temLink = video.modo === "link" && Boolean(lerLinkDeVideo(video.link));
  return {
    video_file_id: temArquivo ? video.arquivoId : null,
    video_link: temLink ? video.link.trim() : null,
    video_flutuante: (temArquivo || temLink) && video.flutuante,
    video_opcoes: lerOpcoesDoVideo(video.opcoes),
  };
}

/* O endereço guardado é o de incorporar; para a pessoa, o de assistir. */
function linkParaMostrar(guardado: string) {
  const link = lerLinkDeVideo(guardado);
  if (!link) return guardado;
  if (link.provedor === "youtube") return `https://www.youtube.com/watch?v=${link.id}`;
  if (link.provedor === "vimeo") {
    const [id, chave] = link.id.split(":");
    return `https://vimeo.com/${id}${chave ? `/${chave}` : ""}`;
  }
  return guardado;
}


type Modulo = {
  podeEnviar: boolean;
  deposito: boolean;
  arquivos: Array<{ id: string; nome: string; status: string }>;
  /* Os produtos com vídeo enviado na galeria. */
  produtosComVideo?: string[];
};

export function VideoDoProdutoEditor({
  produtoId,
  valor,
  aoMudar,
}: {
  /* Para contar os outros produtos com vídeo enviado (o máximo é VIDEO_DO_PRODUTO.produtos). */
  produtoId: string;
  valor: VideoDoProdutoNoCadastro;
  aoMudar: (proximo: VideoDoProdutoNoCadastro) => void;
}) {
  const [modulo, setModulo] = useState<Modulo | null | "carregando">("carregando");
  const [nomeDoArquivo, setNomeDoArquivo] = useState<string | null>(null);
  const [previa, setPrevia] = useState<{ url: string | null; status: string } | null>(null);
  const [progresso, setProgresso] = useState<ProgressoDoEnvio | null>(null);
  const [erro, setErro] = useState<string | null>(null);
  const [escolhendo, setEscolhendo] = useState(false);
  const entrada = useRef<HTMLInputElement | null>(null);
  const envio = useRef<AbortController | null>(null);

  /* A rota dos arquivos responde para quem pode pôr vídeo no produto (assinatura em dia). */
  useEffect(() => {
    let cancelado = false;
    fetch("/api/digitais/arquivos", { cache: "no-store" })
      .then(async (resposta) => {
        if (!resposta.ok) return null;
        const corpo = (await resposta.json().catch(() => null)) as Modulo | null;
        return corpo && corpo.deposito ? corpo : null;
      })
      .catch(() => null)
      .then((resultado) => {
        if (!cancelado) setModulo(resultado);
      });
    return () => {
      cancelado = true;
      envio.current?.abort();
    };
  }, []);

  /* O nome e a prévia do vídeo escolhido. */
  useEffect(() => {
    if (!valor.arquivoId) {
      setPrevia(null);
      setNomeDoArquivo(null);
      return;
    }
    let cancelado = false;
    fetch(`/api/digitais/arquivos/${valor.arquivoId}`, { cache: "no-store" })
      .then((resposta) => (resposta.ok ? resposta.json() : null))
      .then((corpo: { url: string | null; status: string; nome: string } | null) => {
        if (cancelado) return;
        setPrevia(corpo ? { url: corpo.url, status: corpo.status } : null);
        if (corpo?.nome) setNomeDoArquivo(corpo.nome);
      })
      .catch(() => undefined);
    return () => {
      cancelado = true;
    };
  }, [valor.arquivoId]);

  const mudar = useCallback((parcial: Partial<VideoDoProdutoNoCadastro>) => aoMudar({ ...valor, ...parcial }), [aoMudar, valor]);
  const opcoes = valor.opcoes;
  const mudarGaleria = (parcial: Partial<OpcoesDoVideo["galeria"]>) => mudar({ opcoes: { ...opcoes, galeria: { ...opcoes.galeria, ...parcial } } });
  const mudarFlutuante = (parcial: Partial<OpcoesDoVideo["flutuante"]>) => mudar({ opcoes: { ...opcoes, flutuante: { ...opcoes.flutuante, ...parcial } } });

  async function enviar(arquivo: File | undefined) {
    if (!arquivo) return;
    setErro(null);
    if (!arquivo.type.startsWith("video/")) {
      setErro("Escolha um arquivo de vídeo (MP4, MOV ou WEBM).");
      return;
    }
    if (arquivo.size > VIDEO_DO_PRODUTO.bytes) {
      setErro("Vídeo grande demais: o vídeo do produto pode ter até 50 MB. Comprima o vídeo ou use um link do YouTube.");
      return;
    }
    const { duracao } = await medirVideo(arquivo);
    if (duracaoPassou(duracao)) {
      setErro("Vídeo longo demais: o vídeo do produto pode ter até 1 minuto. Corte o vídeo ou use um link do YouTube.");
      return;
    }
    const controle = new AbortController();
    envio.current = controle;
    setProgresso({ enviados: 0, total: arquivo.size, fase: "enviando" });
    try {
      const id = await enviarArquivo(arquivo, setProgresso, controle.signal);
      setNomeDoArquivo(arquivo.name);
      aoMudar({ ...valor, modo: "arquivo", arquivoId: id });
    } catch (e) {
      if (!(e instanceof DOMException && e.name === "AbortError")) {
        setErro(e instanceof Error ? e.message : "Não foi possível enviar o vídeo.");
      }
    } finally {
      envio.current = null;
      setProgresso(null);
      if (entrada.current) entrada.current.value = "";
    }
  }

  const linkLido = valor.link.trim() ? lerLinkDeVideo(valor.link) : null;
  const linkInvalido = Boolean(valor.link.trim()) && (!linkLido || linkLido.provedor === "panda");
  const temVideo = (valor.modo === "arquivo" && Boolean(valor.arquivoId)) || (valor.modo === "link" && Boolean(linkLido) && !linkInvalido);
  const podeEnviar = modulo !== "carregando" && modulo !== null && modulo.podeEnviar;
  /* Quantos OUTROS produtos já têm vídeo enviado: este pode trocar o dele. */
  const outrosComVideo = modulo !== "carregando" && modulo ? (modulo.produtosComVideo ?? []).filter((id) => id !== produtoId).length : 0;
  const semVaga = outrosComVideo >= VIDEO_DO_PRODUTO.produtos;
  const porcentagem = progresso && progresso.total > 0 ? Math.round((progresso.enviados / progresso.total) * 100) : 0;

  return (
    <div className="space-y-4">
      <div className="inline-flex rounded-full bg-slate-100 p-1">
        {(
          [
            ["arquivo", "Vídeo próprio", Video],
            ["link", "Link do YouTube", Link2],
          ] as const
        ).map(([modo, rotulo, Icone]) => (
          <button
            key={modo}
            type="button"
            onClick={() => mudar({ modo })}
            className={cn(
              "inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[12px] font-semibold transition-colors",
              valor.modo === modo ? "bg-white text-[var(--ks-color-primary-strong)] shadow-sm" : "text-slate-500 hover:text-slate-700"
            )}
          >
            <Icone size={13} />
            {rotulo}
          </button>
        ))}
      </div>

      {valor.modo === "arquivo" ? (
        modulo === "carregando" ? (
          <p className="flex items-center gap-2 text-[13px] text-slate-500">
            <Loader2 size={14} className="animate-spin" /> Conferindo seus arquivos…
          </p>
        ) : !podeEnviar && !valor.arquivoId ? (
          <div className="flex items-start gap-3 rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-3.5">
            <Lock size={16} className="mt-0.5 shrink-0 text-slate-400" />
            <p className="text-[13px] leading-5 text-slate-600">
              Para enviar o vídeo do computador, a assinatura do Ktalogu precisa estar em dia e você precisa poder editar produtos.
              Você ainda pode usar um <button type="button" className="font-semibold text-[var(--ks-color-primary-strong)] underline" onClick={() => mudar({ modo: "link" })}>link do YouTube</button>.
            </p>
          </div>
        ) : valor.arquivoId ? (
          <div className="flex flex-col gap-3 sm:flex-row sm:items-start">
            <div className="relative aspect-[9/16] w-[140px] shrink-0 overflow-hidden rounded-xl bg-slate-900">
              {previa?.url ? (
                <video src={previa.url} className="h-full w-full object-cover" muted playsInline controls preload="metadata" />
              ) : (
                <span className="flex h-full w-full items-center justify-center px-3 text-center text-[11px] text-white/70">
                  {previa?.status === "conferindo" || previa?.status === "enviando" ? "Preparando o vídeo…" : "Vídeo"}
                </span>
              )}
            </div>
            <div className="min-w-0 space-y-2">
              <p className="truncate text-[13px] font-semibold text-slate-800">{nomeDoArquivo ?? "Vídeo dos seus arquivos"}</p>
              <div className="flex flex-wrap gap-2">
                {podeEnviar ? (
                  <button type="button" onClick={() => entrada.current?.click()} className="ks-button ks-button-ghost ks-button-sm">
                    <Upload size={13} /> Trocar
                  </button>
                ) : null}
                <button type="button" onClick={() => mudar({ arquivoId: null, flutuante: false })} className="ks-button ks-button-ghost ks-button-sm text-rose-600">
                  <Trash2 size={13} /> Tirar o vídeo
                </button>
              </div>
            </div>
          </div>
        ) : progresso ? (
          <div className="space-y-2 rounded-xl border border-slate-200 px-4 py-3.5">
            <div className="flex items-center justify-between text-[13px] font-semibold text-slate-700">
              <span>{progresso.fase === "conferindo" ? "Conferindo o vídeo…" : `Enviando… ${porcentagem}%`}</span>
              <button type="button" onClick={() => envio.current?.abort()} className="text-[12px] font-semibold text-slate-500 hover:text-rose-600">
                Cancelar
              </button>
            </div>
            <div className="h-1.5 overflow-hidden rounded-full bg-slate-100">
              <div className="h-full rounded-full bg-[var(--ks-color-primary)] transition-[width]" style={{ width: `${porcentagem}%` }} />
            </div>
          </div>
        ) : semVaga ? (
          <div className="flex items-start gap-3 rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-3.5">
            <Lock size={16} className="mt-0.5 shrink-0 text-slate-400" />
            <p className="text-[13px] leading-5 text-slate-600">
              Sua empresa já usa vídeo enviado em <strong>{VIDEO_DO_PRODUTO.produtos} produtos</strong>, o máximo. Tire o vídeo de algum deles ou use um{" "}
              <button type="button" className="font-semibold text-[var(--ks-color-primary-strong)] underline" onClick={() => mudar({ modo: "link" })}>link do YouTube</button> neste.
            </p>
          </div>
        ) : (
          <div className="space-y-2">
            <div className="flex flex-wrap items-center gap-2">
              <button type="button" onClick={() => entrada.current?.click()} className="ks-button ks-button-primary ks-button-sm">
                <Upload size={14} /> Enviar vídeo
              </button>
              <button type="button" onClick={() => setEscolhendo(true)} className="ks-button ks-button-ghost ks-button-sm">
                <FolderOpen size={14} /> Escolher dos meus arquivos
              </button>
            </div>
            <p className="text-[12px] text-slate-500">
              MP4, MOV ou WEBM, até 1 minuto e 50 MB (o ideal é em pé). Vídeo enviado em {outrosComVideo} de {VIDEO_DO_PRODUTO.produtos} produtos.
            </p>
          </div>
        )
      ) : (
        <div className="space-y-2">
          <input
            type="url"
            inputMode="url"
            value={valor.link}
            onChange={(e) => mudar({ link: e.target.value })}
            placeholder="https://www.youtube.com/watch?v=…"
            className="w-full rounded-xl border border-slate-200 px-3.5 py-2.5 text-[14px] outline-none focus:border-[var(--ks-color-primary)] focus:ring-2 focus:ring-[var(--ks-color-primary)]/15"
          />
          {linkInvalido ? (
            <p className="text-[12px] font-medium text-rose-600">Esse link não é de um vídeo do YouTube ou do Vimeo.</p>
          ) : linkLido ? (
            <div className="aspect-video w-full max-w-[360px] overflow-hidden rounded-xl bg-slate-900">
              <iframe src={linkLido.url} title="Prévia do vídeo" className="h-full w-full" allow="encrypted-media; picture-in-picture" allowFullScreen />
            </div>
          ) : (
            <p className="text-[12px] text-slate-500">Cole o link do vídeo (YouTube, Shorts ou Vimeo).</p>
          )}
        </div>
      )}

      {erro ? <p className="text-[12px] font-medium text-rose-600">{erro}</p> : null}

      <input ref={entrada} type="file" accept="video/mp4,video/quicktime,video/webm" className="hidden" onChange={(e) => void enviar(e.target.files?.[0])} />

      <GrupoDeOpcoes titulo="Na galeria" desligado={!temVideo}>
        <Opcao
          titulo="Começar sozinho ao abrir a página"
          texto={valor.flutuante ? "Com o vídeo flutuante ligado, a galeria abre na foto (para não ter dois vídeos rodando)." : "Sem isso, o vídeo espera o cliente tocar no play."}
          ligado={opcoes.galeria.sozinho && !valor.flutuante}
          desligado={!temVideo || valor.flutuante}
          aoMudar={(ligado) => mudarGaleria({ sozinho: ligado, comSom: ligado ? opcoes.galeria.comSom : false })}
        />
        <Opcao
          titulo="Começar com som"
          texto="Só quando ele começa sozinho. Se o navegador do cliente bloquear, começa mudo com o aviso “Toque para ouvir”."
          ligado={opcoes.galeria.comSom && opcoes.galeria.sozinho && !valor.flutuante}
          desligado={!temVideo || !opcoes.galeria.sozinho || valor.flutuante}
          aoMudar={(ligado) => mudarGaleria({ comSom: ligado })}
        />
        <Opcao titulo="Repetir sem parar" ligado={opcoes.galeria.repetir} desligado={!temVideo} aoMudar={(ligado) => mudarGaleria({ repetir: ligado })} />
        <Opcao
          titulo="Mostrar os controles"
          texto="Play, volume, barra de tempo e tela cheia."
          ligado={opcoes.galeria.controles}
          desligado={!temVideo}
          aoMudar={(ligado) => mudarGaleria({ controles: ligado })}
        />
      </GrupoDeOpcoes>

      <div className={cn("flex items-start justify-between gap-4 rounded-xl border border-slate-200 px-4 py-3.5", !temVideo && "opacity-60")}>
        <div className="min-w-0">
          <p className="text-[13px] font-semibold text-slate-800">Vídeo flutuante ao abrir a página</p>
          <p className="mt-0.5 text-[12px] leading-5 text-slate-500">
            O vídeo começa sozinho numa janelinha no canto da página do produto. O cliente toca nela para assistir em tela cheia.
          </p>
        </div>
        <Switch checked={temVideo && valor.flutuante} disabled={!temVideo} onCheckedChange={(ligado) => mudar({ flutuante: ligado })} />
      </div>

      {temVideo && valor.flutuante ? (
        <GrupoDeOpcoes titulo="Na janelinha flutuante">
          <Opcao
            titulo="Começar com som"
            texto="Se o navegador do cliente bloquear, começa mudo com o aviso “Toque para ouvir”."
            ligado={opcoes.flutuante.comSom}
            aoMudar={(ligado) => mudarFlutuante({ comSom: ligado })}
          />
          <Opcao titulo="Repetir sem parar" ligado={opcoes.flutuante.repetir} aoMudar={(ligado) => mudarFlutuante({ repetir: ligado })} />
        </GrupoDeOpcoes>
      ) : null}

      {escolhendo ? (
        <EscolherDaBiblioteca
          titulo="Escolher um vídeo"
          so="video"
          aoFechar={() => setEscolhendo(false)}
          aoEscolher={(arquivo) => {
            setEscolhendo(false);
            const tamanho = Number((arquivo as { tamanho?: number }).tamanho ?? 0);
            if (tamanho > VIDEO_DO_PRODUTO.bytes) {
              setErro("Esse vídeo passa de 50 MB, o máximo do vídeo do produto.");
              return;
            }
            if (duracaoPassou(arquivo.duracao)) {
              setErro("Esse vídeo passa de 1 minuto, o máximo do vídeo do produto.");
              return;
            }
            setErro(null);
            setNomeDoArquivo(arquivo.nome);
            aoMudar({ ...valor, modo: "arquivo", arquivoId: arquivo.id });
          }}
        />
      ) : null}
    </div>
  );
}

function GrupoDeOpcoes({ titulo, desligado, children }: { titulo: string; desligado?: boolean; children: React.ReactNode }) {
  return (
    <div className={cn("rounded-xl border border-slate-200", desligado && "opacity-60")}>
      <p className="border-b border-slate-100 px-4 py-2.5 text-[11px] font-bold uppercase tracking-[0.12em] text-slate-500">{titulo}</p>
      <div className="divide-y divide-slate-100">{children}</div>
    </div>
  );
}

function Opcao({
  titulo,
  texto,
  ligado,
  desligado,
  aoMudar,
}: {
  titulo: string;
  texto?: string;
  ligado: boolean;
  desligado?: boolean;
  aoMudar: (ligado: boolean) => void;
}) {
  return (
    <div className="flex items-start justify-between gap-4 px-4 py-3">
      <div className="min-w-0">
        <p className="text-[13px] font-semibold text-slate-800">{titulo}</p>
        {texto ? <p className="mt-0.5 text-[12px] leading-5 text-slate-500">{texto}</p> : null}
      </div>
      <Switch checked={ligado} disabled={desligado} onCheckedChange={aoMudar} />
    </div>
  );
}
