"use client";

import { useRef, useState } from "react";

import { enviarArquivo, ErroDoEnvio, type RotasDoEnvio } from "@/components/digitais/enviar-arquivo";

/*
 * O vídeo (ou arquivo) que a pessoa manda ao assistente para os produtos
 * digitais. O envio é o mesmo da biblioteca do painel (em partes, direto
 * para o depósito, três de cada vez, tentando de novo quando a internet
 * falha); só as rotas são as do código deste link.
 */

type Estado =
  | { fase: "parado" }
  | { fase: "enviando"; enviados: number; total: number; conferindo: boolean }
  | { fase: "pronto"; nome: string }
  | { fase: "erro"; mensagem: string };

function tamanho(bytes: number) {
  if (bytes >= 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024 * 1024)).toLocaleString("pt-BR", { maximumFractionDigits: 1 })} GB`;
  if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toLocaleString("pt-BR", { maximumFractionDigits: 1 })} MB`;
  return `${Math.max(1, Math.round(bytes / 1024))} KB`;
}

const VIDEO = /\.(mp4|m4v|mov|webm)$/i;

export function EnvioDigital({
  codigo,
  loja,
  paraQue,
  soVideo,
  limite,
  recebido,
}: {
  codigo: string;
  loja: string | null;
  paraQue: string | null;
  soVideo: boolean;
  limite: string;
  recebido: string | null;
}) {
  const entrada = useRef<HTMLInputElement>(null);
  const cancelar = useRef<AbortController | null>(null);
  const [estado, setEstado] = useState<Estado>({ fase: "parado" });
  const [arrastando, setArrastando] = useState(false);
  const enviando = estado.fase === "enviando";
  const base = `/api/enviar/${encodeURIComponent(codigo)}/digital`;
  const rotas: RotasDoEnvio = {
    abrir: base,
    partes: (id) => `${base}?etapa=partes&arquivo=${id}`,
    concluir: (id) => `${base}?etapa=concluir&arquivo=${id}`,
    cancelar: (id) => `${base}?arquivo=${id}`,
  };

  async function enviar(arquivo: File) {
    if (enviando) return;
    if (soVideo && !VIDEO.test(arquivo.name) && !arquivo.type.startsWith("video/")) {
      setEstado({ fase: "erro", mensagem: "Este arquivo não é um vídeo. Envie MP4, MOV, M4V ou WEBM." });
      return;
    }
    const controle = new AbortController();
    cancelar.current = controle;
    setEstado({ fase: "enviando", enviados: 0, total: arquivo.size, conferindo: false });
    try {
      await enviarArquivo(
        arquivo,
        (progresso) => setEstado({ fase: "enviando", enviados: progresso.enviados, total: progresso.total, conferindo: progresso.fase === "conferindo" }),
        controle.signal,
        undefined,
        rotas
      );
      setEstado({ fase: "pronto", nome: arquivo.name });
    } catch (erro) {
      if (erro instanceof DOMException && erro.name === "AbortError") {
        setEstado({ fase: "parado" });
        return;
      }
      setEstado({ fase: "erro", mensagem: erro instanceof ErroDoEnvio ? erro.message : "Não deu para enviar. Confira a internet e tente de novo." });
    } finally {
      cancelar.current = null;
    }
  }

  function abrirEscolha() {
    if (!enviando) entrada.current?.click();
  }

  const coisa = soVideo ? "o vídeo" : "o arquivo";
  const titulo = paraQue ? `Envie ${coisa} (${paraQue})` : `Envie ${coisa}`;
  const porcentagem = estado.fase === "enviando" && estado.total ? Math.round((estado.enviados / estado.total) * 100) : 0;

  return (
    <section>
      <h1 className="envio-titulo">{titulo}</h1>
      <p className="envio-sub">
        {loja ? (
          <>
            Enviando para <strong>{loja}</strong>.{" "}
          </>
        ) : null}
        Escolha {coisa} no celular ou no computador e deixe esta página aberta até terminar. Depois, volte para a conversa com o assistente.
      </p>

      {recebido && estado.fase !== "pronto" ? (
        <p className="envio-ja">
          {soVideo ? "Um vídeo" : "Um arquivo"} já foi enviado por este link ({recebido}). Se enviar outro, ele passa a valer no lugar; o anterior continua em Arquivos e espaço.
        </p>
      ) : null}

      <div
        className="envio-alvo"
        role="button"
        tabIndex={0}
        aria-label={`Escolher ${coisa} para enviar`}
        data-arrastando={arrastando ? "sim" : "nao"}
        onClick={abrirEscolha}
        onKeyDown={(evento) => {
          if (evento.key === "Enter" || evento.key === " ") {
            evento.preventDefault();
            abrirEscolha();
          }
        }}
        onDragOver={(evento) => {
          evento.preventDefault();
          setArrastando(true);
        }}
        onDragLeave={() => setArrastando(false)}
        onDrop={(evento) => {
          evento.preventDefault();
          setArrastando(false);
          const solto = evento.dataTransfer.files?.[0];
          if (solto) void enviar(solto);
        }}
      >
        <svg width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="#7c3aed" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          {soVideo ? (
            <>
              <rect x="2" y="5" width="15" height="14" rx="3" />
              <path d="m17 10 5-3v10l-5-3" />
            </>
          ) : (
            <>
              <path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" />
              <path d="M14 3v5h5" />
            </>
          )}
        </svg>
        <button
          type="button"
          className="envio-botao"
          disabled={enviando}
          onClick={(evento) => {
            evento.stopPropagation();
            abrirEscolha();
          }}
        >
          {estado.fase === "pronto" || recebido ? (soVideo ? "Escolher outro vídeo" : "Escolher outro arquivo") : soVideo ? "Escolher vídeo" : "Escolher arquivo"}
        </button>
        <span className="envio-alvo-texto">
          ou <strong>arraste {coisa} para cá</strong>
        </span>
        <input
          ref={entrada}
          className="envio-escondido"
          type="file"
          accept={soVideo ? "video/mp4,video/quicktime,video/webm,.mp4,.m4v,.mov,.webm" : undefined}
          tabIndex={-1}
          onChange={(evento) => {
            const escolhido = evento.target.files?.[0];
            evento.target.value = "";
            if (escolhido) void enviar(escolhido);
          }}
        />
      </div>

      {estado.fase === "enviando" ? (
        <div className="envio-previa">
          <div className="envio-previa-info">
            <div className="envio-previa-nome">{estado.conferindo ? "Conferindo o arquivo…" : `Enviando ${porcentagem}%`}</div>
            <div className="envio-previa-detalhe">
              {tamanho(estado.enviados)} de {tamanho(estado.total)}. Não feche esta página.
            </div>
            <div className="envio-barra" role="progressbar" aria-valuemin={0} aria-valuemax={100} aria-valuenow={porcentagem}>
              <span style={{ width: `${estado.conferindo ? 100 : porcentagem}%` }} />
            </div>
            {!estado.conferindo ? (
              <button type="button" className="envio-botao-leve" onClick={() => cancelar.current?.abort()}>
                Cancelar o envio
              </button>
            ) : null}
          </div>
        </div>
      ) : null}

      {estado.fase === "pronto" ? (
        <div className="envio-mensagem" data-tipo="ok" role="status">
          <strong>Pronto!</strong>
          {estado.nome} chegou. Volte para a conversa e diga &quot;enviei&quot;.
        </div>
      ) : null}
      {estado.fase === "erro" ? (
        <div className="envio-mensagem" data-tipo="erro" role="alert">
          {estado.mensagem}
        </div>
      ) : null}

      <p className="envio-dica">
        {soVideo ? "MP4, MOV, M4V ou WEBM" : "Vídeo, PDF, imagem, ZIP, áudio ou documento"}, até {limite} por arquivo. O arquivo fica em Arquivos e espaço, nos produtos digitais. Este link vale 24 horas.
      </p>
    </section>
  );
}
