"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ArrowDownToLine, CheckCircle2, Loader2, Lock, MoreHorizontal, RotateCcw, Trash2, UploadCloud, X } from "lucide-react";

import { AreaFechada, CarregandoArea, ErroDaArea, FalhaDaArea, pedirDigitais } from "@/components/digitais/comum";
import { enviarArquivo, retomarEnvio, type ProgressoDoEnvio } from "@/components/digitais/enviar-arquivo";
import { COR_DA_CATEGORIA, ROTULO_DA_CATEGORIA, SeloDoArquivo } from "@/components/digitais/selo-do-arquivo";
import { Aviso } from "@/components/ui/aviso";
import CaixaDeConfirmacao, { type Confirmacao } from "@/components/ui/caixa-de-confirmacao";
import { FIO_DA_LINHA } from "@/components/ui/folha-de-ajustes";
import { PageHeader } from "@/components/ui/page-header";
import { faixaDoEspaco } from "@/lib/digitais/limites";
import { tamanhoLegivel } from "@/lib/digitais/nome-do-arquivo";

type Arquivo = {
  id: string;
  nome: string;
  extensao: string;
  categoria: string;
  tamanho: number;
  tamanhoLegivel: string;
  status: string;
  motivo: string | null;
  criadoEm: string;
  duracao: number | null;
  paginas: number | null;
  usadoEm: string[];
  produtos: string[];
};

type Resposta = {
  podeEnviar: boolean;
  deposito: boolean;
  espaco: {
    usado: number;
    arquivos: number;
    porCategoria: Record<string, { bytes: number; arquivos: number }>;
    total: number;
    porArquivo: number;
    teste: boolean;
  };
  arquivos: Arquivo[];
};

type Envio = {
  chave: string;
  nome: string;
  tamanho: number;
  categoria: string;
  extensao: string;
  progresso: ProgressoDoEnvio | null;
  erro: string | null;
  controle: AbortController;
  inicio: number;
};

const ORDEM_DAS_CATEGORIAS = ["video", "pdf", "imagem", "compactado", "audio", "documento", "outro"];

function extensaoDoNome(nome: string) {
  const ponto = nome.lastIndexOf(".");
  return ponto > 0 ? nome.slice(ponto + 1).toLowerCase() : "";
}

function categoriaDoNome(nome: string) {
  const ext = extensaoDoNome(nome);
  if (["mp4", "mov", "webm", "m4v"].includes(ext)) return "video";
  if (ext === "pdf") return "pdf";
  if (["jpg", "jpeg", "png", "webp", "gif", "svg", "tif", "tiff", "heic", "psd", "ai", "eps", "cdr"].includes(ext)) return "imagem";
  if (ext === "zip") return "compactado";
  if (["mp3", "wav", "m4a", "aac", "flac", "ogg"].includes(ext)) return "audio";
  return "outro";
}

function duracaoLegivel(segundos: number) {
  const total = Math.round(segundos);
  const h = Math.floor(total / 3600);
  const m = Math.floor((total % 3600) / 60);
  const s = total % 60;
  return h > 0 ? `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}` : `${m}:${String(s).padStart(2, "0")}`;
}

function dataCurta(iso: string) {
  return new Intl.DateTimeFormat("pt-BR", { day: "2-digit", month: "2-digit" }).format(new Date(iso));
}

function tempoRestante(envio: Envio, agora: number) {
  if (!envio.progresso || envio.progresso.enviados <= 0) return null;
  const decorrido = (agora - envio.inicio) / 1000;
  if (decorrido < 3) return null;
  const ritmo = envio.progresso.enviados / decorrido;
  const falta = (envio.progresso.total - envio.progresso.enviados) / Math.max(ritmo, 1);
  if (falta < 60) return "menos de 1 min";
  return `${Math.ceil(falta / 60)} min`;
}

export default function ArquivosEEspaco() {
  const [dados, setDados] = useState<Resposta | null>(null);
  const [erro, setErro] = useState<Error | null>(null);
  const [envios, setEnvios] = useState<Envio[]>([]);
  const [soSemUso, setSoSemUso] = useState(false);
  const [aviso, setAviso] = useState<{ tom: "bom" | "ruim"; texto: string } | null>(null);
  const [confirmacao, setConfirmacao] = useState<Confirmacao | null>(null);
  const [ocupado, setOcupado] = useState(false);
  const [agora, setAgora] = useState(() => Date.now());
  const [menuAberto, setMenuAberto] = useState<string | null>(null);
  const escolherRef = useRef<HTMLInputElement>(null);
  const retomarRef = useRef<HTMLInputElement>(null);
  const retomandoRef = useRef<Arquivo | null>(null);

  const carregar = useCallback(
    () =>
      pedirDigitais<Resposta>("/api/digitais/arquivos")
        .then((resposta) => {
          setDados(resposta);
          setErro(null);
        })
        .catch((e: unknown) => setErro(e instanceof Error ? e : new Error("Não foi possível carregar."))),
    []
  );

  useEffect(() => {
    void carregar();
  }, [carregar]);

  /* Relógio só enquanto há envio, para o "faltam X min". */
  useEffect(() => {
    if (!envios.length) return;
    const relogio = setInterval(() => setAgora(Date.now()), 1000);
    return () => clearInterval(relogio);
  }, [envios.length]);

  const atualizarEnvio = (chave: string, parte: Partial<Envio>) =>
    setEnvios((lista) => lista.map((envio) => (envio.chave === chave ? { ...envio, ...parte } : envio)));

  const comecarEnvios = (arquivos: FileList | null) => {
    if (!arquivos?.length) return;
    for (const arquivo of Array.from(arquivos)) {
      const chave = `${arquivo.name}-${arquivo.size}-${Math.random().toString(36).slice(2, 8)}`;
      const controle = new AbortController();
      const envio: Envio = {
        chave,
        nome: arquivo.name,
        tamanho: arquivo.size,
        categoria: categoriaDoNome(arquivo.name),
        extensao: extensaoDoNome(arquivo.name),
        progresso: null,
        erro: null,
        controle,
        inicio: Date.now(),
      };
      setEnvios((lista) => [...lista, envio]);
      void enviarArquivo(arquivo, (progresso) => atualizarEnvio(chave, { progresso }), controle.signal)
        .then(() => {
          setEnvios((lista) => lista.filter((item) => item.chave !== chave));
          setAviso({ tom: "bom", texto: `${arquivo.name} chegou e está pronto para usar.` });
          void carregar();
        })
        .catch((falha: unknown) => {
          if (falha instanceof DOMException && falha.name === "AbortError") {
            setEnvios((lista) => lista.filter((item) => item.chave !== chave));
            void carregar();
            return;
          }
          atualizarEnvio(chave, { erro: falha instanceof Error ? falha.message : "O envio não deu certo." });
          void carregar();
        });
    }
  };

  const retomar = (arquivo: File) => {
    const alvo = retomandoRef.current;
    retomandoRef.current = null;
    if (!alvo) return;
    if (arquivo.name !== alvo.nome || arquivo.size !== alvo.tamanho) {
      setAviso({ tom: "ruim", texto: `Escolha o mesmo arquivo: ${alvo.nome} (${alvo.tamanhoLegivel}).` });
      return;
    }
    const chave = `retomar-${alvo.id}`;
    const controle = new AbortController();
    setEnvios((lista) => [
      ...lista.filter((item) => item.chave !== chave),
      { chave, nome: alvo.nome, tamanho: alvo.tamanho, categoria: alvo.categoria, extensao: alvo.extensao, progresso: null, erro: null, controle, inicio: Date.now() },
    ]);
    void retomarEnvio(alvo.id, arquivo, (progresso) => atualizarEnvio(chave, { progresso }), controle.signal)
      .then(() => {
        setEnvios((lista) => lista.filter((item) => item.chave !== chave));
        setAviso({ tom: "bom", texto: `${alvo.nome} terminou de chegar.` });
        void carregar();
      })
      .catch((falha: unknown) => {
        if (falha instanceof DOMException && falha.name === "AbortError") {
          setEnvios((lista) => lista.filter((item) => item.chave !== chave));
          return;
        }
        atualizarEnvio(chave, { erro: falha instanceof Error ? falha.message : "O envio não deu certo." });
      });
  };

  const pedirParaApagar = (arquivo: Arquivo) => {
    setMenuAberto(null);
    const enviando = arquivo.status === "enviando" || arquivo.status === "conferindo";
    setConfirmacao({
      titulo: enviando ? "Cancelar este envio?" : "Apagar este arquivo?",
      texto: enviando
        ? `${arquivo.nome} para de subir e o espaço reservado volta para você.`
        : `${arquivo.nome} sai da sua biblioteca e libera ${arquivo.tamanhoLegivel}.`,
      confirmar: enviando ? "Cancelar envio" : "Apagar",
      cancelar: "Voltar",
      tom: "perigo",
      aoConfirmar: async () => {
        setOcupado(true);
        try {
          await pedirDigitais(`/api/digitais/arquivos/${arquivo.id}`, { method: "DELETE" });
          setAviso({ tom: "bom", texto: enviando ? "Envio cancelado." : "Arquivo apagado." });
          await carregar();
        } catch (e) {
          setAviso({ tom: "ruim", texto: e instanceof Error ? e.message : "Não foi possível apagar." });
        } finally {
          setOcupado(false);
          setConfirmacao(null);
        }
      },
    });
  };

  const lista = useMemo(() => {
    const todos = dados?.arquivos ?? [];
    return soSemUso ? todos.filter((a) => a.status === "pronto" && a.usadoEm.length === 0) : todos;
  }, [dados, soSemUso]);
  const semUso = (dados?.arquivos ?? []).filter((a) => a.status === "pronto" && a.usadoEm.length === 0).length;

  if (erro instanceof ErroDaArea && erro.status === 403) return <AreaFechada erro={erro} />;
  if (erro && !dados) return <FalhaDaArea erro={erro} aoTentarDeNovo={() => void carregar()} />;
  if (!dados) return <CarregandoArea />;

  const { espaco } = dados;
  const sobra = Math.max(0, espaco.total - espaco.usado);
  const faixa = faixaDoEspaco(espaco.usado, espaco.total);
  const podeEnviar = dados.podeEnviar && dados.deposito;

  return (
    <div className="space-y-5">
      <PageHeader
        eyebrow="Arquivos"
        title="Arquivos e espaço"
        subtitle="Tudo o que você enviou para os conteúdos em vídeo e produtos digitais, num lugar só."
        actions={
          <div className="flex flex-wrap items-center gap-2">
            {semUso > 0 || soSemUso ? (
              <button type="button" onClick={() => setSoSemUso((v) => !v)} className={`ks-button ${soSemUso ? "ks-button-primary" : "ks-button-soft"}`}>
                {soSemUso ? "Ver todos" : `Ver sem uso (${semUso})`}
              </button>
            ) : null}
            {dados.podeEnviar ? (
              <button type="button" disabled={!podeEnviar} onClick={() => escolherRef.current?.click()} className="ks-button ks-button-primary">
                <UploadCloud size={16} />
                Enviar arquivos
              </button>
            ) : null}
            <input
              ref={escolherRef}
              type="file"
              multiple
              className="hidden"
              onChange={(evento) => {
                comecarEnvios(evento.target.files);
                evento.target.value = "";
              }}
            />
            <input
              ref={retomarRef}
              type="file"
              className="hidden"
              onChange={(evento) => {
                const arquivo = evento.target.files?.[0];
                evento.target.value = "";
                if (arquivo) retomar(arquivo);
              }}
            />
          </div>
        }
      />

      {!dados.deposito ? <Aviso tom="neutro">O envio de arquivos ainda está sendo ligado neste servidor. A lista continua aqui.</Aviso> : null}
      {aviso ? (
        <Aviso tom={aviso.tom} aoFechar={() => setAviso(null)}>
          {aviso.texto}
        </Aviso>
      ) : null}
      {faixa !== "folga" ? (
        <Aviso tom="atencao">
          {faixa === "cheio"
            ? "Seu espaço acabou. Envios novos param, mas nada é apagado e as vendas continuam. Apague arquivos sem uso para liberar."
            : `Seu espaço está quase no fim: sobram ${tamanhoLegivel(sobra)}.`}
        </Aviso>
      ) : null}

      <section className="grid gap-5 rounded-2xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] p-5 shadow-[var(--ks-shadow-subtle)] lg:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)] sm:p-6">
        <div className="min-w-0">
          <p className="flex flex-wrap items-baseline gap-x-2 gap-y-1">
            <span className="ks-num whitespace-nowrap text-3xl font-extrabold tracking-tight text-[var(--ks-color-text-primary)]">{tamanhoLegivel(espaco.usado)}</span>
            <span className="text-sm text-[var(--ks-color-text-muted)]">
              de {tamanhoLegivel(espaco.total)} usados · sobram {tamanhoLegivel(sobra)}
            </span>
          </p>
          <div className="mt-3 flex h-3.5 overflow-hidden rounded-full bg-[var(--ks-color-bg-inset)]">
            {ORDEM_DAS_CATEGORIAS.map((categoria) => {
              const bytes = espaco.porCategoria[categoria]?.bytes ?? 0;
              if (!bytes) return null;
              return (
                <span
                  key={categoria}
                  title={`${ROTULO_DA_CATEGORIA[categoria]}: ${tamanhoLegivel(bytes)}`}
                  style={{ width: `${Math.max(0.8, (bytes / espaco.total) * 100)}%`, background: COR_DA_CATEGORIA[categoria] }}
                />
              );
            })}
          </div>
          <div className="mt-3 grid gap-x-5 gap-y-1.5 text-xs text-[var(--ks-color-text-muted)] sm:grid-cols-2">
            {ORDEM_DAS_CATEGORIAS.filter((categoria) => espaco.porCategoria[categoria]?.arquivos).map((categoria) => (
              <span key={categoria} className="flex items-center gap-2">
                <i className="inline-block h-2.5 w-2.5 rounded-[3px]" style={{ background: COR_DA_CATEGORIA[categoria] }} />
                {ROTULO_DA_CATEGORIA[categoria]} · {tamanhoLegivel(espaco.porCategoria[categoria].bytes)} · {espaco.porCategoria[categoria].arquivos}{" "}
                {espaco.porCategoria[categoria].arquivos === 1 ? "arquivo" : "arquivos"}
              </span>
            ))}
            {espaco.arquivos === 0 ? <span>Nenhum arquivo ainda.</span> : null}
          </div>
        </div>
        <ul className="grid content-start gap-3 text-[13px] leading-5 text-[var(--ks-color-text-muted)]">
          <li className="flex gap-3">
            <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-[color:rgba(14,158,112,0.1)] text-[var(--ks-emerald)]">
              <ArrowDownToLine size={16} />
            </span>
            <span>
              <b className="text-[var(--ks-color-text-primary)]">Download e vídeo assistido não gastam espaço.</b> Só conta o que está guardado.
            </span>
          </li>
          <li className="flex gap-3">
            <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-[color:rgba(14,158,112,0.1)] text-[var(--ks-emerald)]">
              <CheckCircle2 size={16} />
            </span>
            <span>
              <b className="text-[var(--ks-color-text-primary)]">Até {tamanhoLegivel(espaco.porArquivo)} por arquivo.</b> Vídeo grande sobe em partes e continua de onde parou se a internet cair.
            </span>
          </li>
          <li className="flex gap-3">
            <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-[color:rgba(14,158,112,0.1)] text-[var(--ks-emerald)]">
              <Lock size={16} />
            </span>
            <span>
              <b className="text-[var(--ks-color-text-primary)]">Só quem comprou acessa.</b> Cada download usa um link que vence em minutos.
            </span>
          </li>
        </ul>
      </section>

      {envios.length ? (
        <section className="space-y-2">
          {envios.map((envio) => {
            const fracao = envio.progresso ? (envio.progresso.enviados / Math.max(1, envio.progresso.total)) * 100 : 0;
            const restante = tempoRestante(envio, agora);
            return (
              <div key={envio.chave} className="flex items-center gap-3 rounded-2xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] px-4 py-3">
                <SeloDoArquivo categoria={envio.categoria} texto={envio.extensao || "arq"} />
                <div className="min-w-0 flex-1">
                  <p className="truncate text-sm font-semibold text-[var(--ks-color-text-primary)]">
                    {envio.nome} <span className="font-normal text-[var(--ks-color-text-muted)]">· {tamanhoLegivel(envio.tamanho)}</span>
                  </p>
                  {envio.erro ? (
                    <p className="mt-0.5 text-xs font-semibold text-[var(--ks-color-status-danger)]">{envio.erro}</p>
                  ) : (
                    <div className="mt-1.5 h-1.5 overflow-hidden rounded-full bg-[var(--ks-color-bg-inset)]">
                      <div className="h-full rounded-full bg-gradient-to-r from-violet-500 to-purple-600 transition-[width] duration-300" style={{ width: `${fracao}%` }} />
                    </div>
                  )}
                </div>
                {!envio.erro ? (
                  <span className="ks-num shrink-0 rounded-full bg-[var(--ks-brand-50)] px-2.5 py-1 text-xs font-bold text-[var(--ks-brand-600)]">
                    {envio.progresso?.fase === "conferindo" ? "conferindo..." : `${Math.floor(fracao)}%${restante ? ` · ${restante}` : ""}`}
                  </span>
                ) : null}
                <button
                  type="button"
                  aria-label={envio.erro ? "Fechar" : "Cancelar envio"}
                  onClick={() => {
                    if (envio.erro) setEnvios((lista) => lista.filter((item) => item.chave !== envio.chave));
                    else envio.controle.abort();
                  }}
                  className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-[var(--ks-color-text-soft)] hover:bg-[var(--ks-color-bg-hover)]"
                >
                  <X size={16} />
                </button>
              </div>
            );
          })}
        </section>
      ) : null}

      <section className="overflow-hidden rounded-2xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] shadow-[var(--ks-shadow-subtle)]">
        <div className="hidden grid-cols-[minmax(0,1fr)_110px_minmax(0,220px)_80px_44px] gap-4 border-b border-[var(--ks-color-border-subtle)] px-5 py-3 text-[11px] font-bold uppercase tracking-[0.12em] text-[var(--ks-color-text-soft)] md:grid">
          <span>Arquivo</span>
          <span>Tamanho</span>
          <span>Onde está</span>
          <span>Enviado</span>
          <span />
        </div>
        {lista.length === 0 ? (
          <div className="flex flex-col items-center gap-3 px-6 py-14 text-center">
            <span className="flex h-12 w-12 items-center justify-center rounded-2xl bg-[var(--ks-brand-50)] text-[var(--ks-brand-600)]">
              <UploadCloud size={22} />
            </span>
            <p className="text-sm font-semibold text-[var(--ks-color-text-primary)]">{soSemUso ? "Nenhum arquivo sem uso." : "Nenhum arquivo ainda."}</p>
            {!soSemUso ? (
              <p className="max-w-sm text-xs leading-5 text-[var(--ks-color-text-muted)]">
                Envie vídeos, PDFs, ZIPs e imagens. Depois você escolhe em que produto cada um entra.
              </p>
            ) : null}
          </div>
        ) : (
          <ul className="px-2 sm:px-3">
            {lista.map((arquivo) => {
              const enviando = arquivo.status === "enviando" || arquivo.status === "conferindo";
              const detalhe = arquivo.status === "recusado"
                ? arquivo.motivo || "Recusado na conferência."
                : enviando
                  ? "Envio parado: escolha o mesmo arquivo para continuar."
                  : arquivo.duracao
                    ? duracaoLegivel(arquivo.duracao)
                    : arquivo.paginas
                      ? `${arquivo.paginas} páginas`
                      : arquivo.extensao.toUpperCase();
              return (
                <li key={arquivo.id} className={`grid grid-cols-[minmax(0,1fr)_auto] items-center gap-4 px-2 py-3 md:grid-cols-[minmax(0,1fr)_110px_minmax(0,220px)_80px_44px] ${FIO_DA_LINHA}`}>
                  <div className="flex min-w-0 items-center gap-3">
                    <SeloDoArquivo categoria={arquivo.categoria} texto={arquivo.extensao || "arq"} />
                    <div className="min-w-0">
                      <p className="truncate text-sm font-semibold text-[var(--ks-color-text-primary)]" title={arquivo.nome}>
                        {arquivo.nome}
                      </p>
                      <p className={`truncate text-xs ${arquivo.status === "recusado" ? "font-semibold text-[var(--ks-color-status-danger)]" : "text-[var(--ks-color-text-muted)]"}`}>
                        {detalhe}
                        <span className="md:hidden"> · {arquivo.tamanhoLegivel}</span>
                      </p>
                    </div>
                  </div>
                  <span className="ks-num hidden text-sm text-[var(--ks-color-text-secondary)] md:block">{arquivo.tamanhoLegivel}</span>
                  <span className="hidden min-w-0 text-sm text-[var(--ks-color-text-secondary)] md:block">
                    {arquivo.usadoEm.length ? (
                      <span className="block truncate" title={arquivo.usadoEm.join(", ")}>
                        {arquivo.usadoEm.join(", ")}
                      </span>
                    ) : arquivo.status === "pronto" ? (
                      <span className="rounded-full bg-[var(--ks-color-bg-inset)] px-2.5 py-0.5 text-xs font-semibold text-[var(--ks-color-text-muted)]">sem uso</span>
                    ) : enviando ? (
                      <span className="rounded-full bg-[var(--ks-brand-50)] px-2.5 py-0.5 text-xs font-semibold text-[var(--ks-brand-600)]">enviando</span>
                    ) : (
                      <span className="rounded-full bg-[color:rgba(214,48,76,0.1)] px-2.5 py-0.5 text-xs font-semibold text-[var(--ks-color-status-danger)]">recusado</span>
                    )}
                  </span>
                  <span className="ks-num hidden text-sm text-[var(--ks-color-text-muted)] md:block">{dataCurta(arquivo.criadoEm)}</span>
                  <div className="relative flex justify-end">
                    {dados.podeEnviar ? (
                      <>
                        {enviando && podeEnviar ? (
                          <button
                            type="button"
                            title="Continuar o envio"
                            onClick={() => {
                              retomandoRef.current = arquivo;
                              retomarRef.current?.click();
                            }}
                            className="mr-1 flex h-8 w-8 items-center justify-center rounded-full text-[var(--ks-brand-600)] hover:bg-[var(--ks-brand-50)]"
                          >
                            <RotateCcw size={16} />
                          </button>
                        ) : null}
                        <button
                          type="button"
                          aria-label="Mais ações"
                          onClick={() => setMenuAberto((atual) => (atual === arquivo.id ? null : arquivo.id))}
                          className="flex h-8 w-8 items-center justify-center rounded-full text-[var(--ks-color-text-soft)] hover:bg-[var(--ks-color-bg-hover)]"
                        >
                          <MoreHorizontal size={18} />
                        </button>
                        {menuAberto === arquivo.id ? (
                          <div className="absolute right-0 top-9 z-20 w-48 rounded-xl border border-[var(--ks-color-border-subtle)] bg-white p-1 shadow-[0_12px_30px_rgba(26,26,43,0.16)]">
                            <button
                              type="button"
                              onClick={() => pedirParaApagar(arquivo)}
                              className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-semibold text-[var(--ks-color-status-danger)] hover:bg-[color:rgba(214,48,76,0.08)]"
                            >
                              <Trash2 size={15} />
                              {enviando ? "Cancelar envio" : "Apagar arquivo"}
                            </button>
                          </div>
                        ) : null}
                      </>
                    ) : null}
                  </div>
                </li>
              );
            })}
          </ul>
        )}
      </section>

      {envios.some((envio) => !envio.erro) ? (
        <p className="flex items-center gap-2 text-xs text-[var(--ks-color-text-muted)]">
          <Loader2 className="h-3.5 w-3.5 animate-spin" />
          Deixe esta página aberta até os envios terminarem.
        </p>
      ) : null}

      <CaixaDeConfirmacao pedido={confirmacao} ocupado={ocupado} aoFechar={() => (ocupado ? undefined : setConfirmacao(null))} />
    </div>
  );
}
