"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ArrowDown, ArrowUp, FileText, GripVertical, Lock, MoreHorizontal, Paperclip, Play, Plus, Radio } from "lucide-react";

import { pedirDigitais } from "@/components/digitais/comum";
import { enviarArquivo, medirVideo } from "@/components/digitais/enviar-arquivo";
import type { Confirmacao } from "@/components/ui/caixa-de-confirmacao";
import { duracaoLegivel, relogio, rotuloDaRegra, type TipoDeAula } from "@/lib/digitais/curso";

import { EditorDaAula, EditorDoModulo, type EnvioDaAula } from "./editor-da-aula";
import type { Aula, Modulo } from "./tipos";

/*
 * A aba Conteúdo (prévia 8): à esquerda, módulos e aulas (arrastar para
 * ordenar, ou o menu "…" no celular); à direita, o que estiver escolhido.
 */

const ICONE: Record<TipoDeAula, typeof Play> = { video: Play, texto: FileText, materiais: Paperclip, ao_vivo: Radio };

type Escolhido = { tipo: "aula"; id: string } | { tipo: "modulo"; id: string } | null;
type Arrastando = { tipo: "aula"; aulaId: string; moduloId: string } | { tipo: "modulo"; moduloId: string } | null;

export function ConteudoDoCurso({
  cursoId,
  modulos,
  podeEditar,
  aoMudar,
  aoAvisar,
  aoConfirmar,
}: {
  cursoId: string;
  modulos: Modulo[];
  podeEditar: boolean;
  aoMudar: () => Promise<void> | void;
  aoAvisar: (tom: "bom" | "ruim" | "atencao", texto: string) => void;
  aoConfirmar: (pedido: Confirmacao) => void;
}) {
  /* Ordem nova aparece na hora (antes de o servidor responder); quando o pai
     recarrega, a lista dele volta a mandar. */
  const [otimista, setOtimista] = useState<{ base: Modulo[]; lista: Modulo[] } | null>(null);
  const lista = otimista && otimista.base === modulos ? otimista.lista : modulos;
  const setLista = (mudar: (atual: Modulo[]) => Modulo[]) => setOtimista({ base: modulos, lista: mudar(lista) });
  const [escolhido, setEscolhido] = useState<Escolhido>(() => {
    const primeira = modulos.flatMap((m) => m.aulas)[0];
    return primeira ? { tipo: "aula", id: primeira.id } : modulos[0] ? { tipo: "modulo", id: modulos[0].id } : null;
  });
  const [envios, setEnvios] = useState<Record<string, EnvioDaAula>>({});
  const [arrastando, setArrastando] = useState<Arrastando>(null);
  const [alvo, setAlvo] = useState<{ moduloId: string; antesDe: string | null } | null>(null);
  const [menu, setMenu] = useState<string | null>(null);
  const [criando, setCriando] = useState<string | null>(null);
  const vivo = useRef(true);

  useEffect(() => {
    vivo.current = true;
    return () => {
      vivo.current = false;
    };
  }, []);

  useEffect(() => {
    if (!menu) return;
    const fechar = () => setMenu(null);
    window.addEventListener("click", fechar);
    return () => window.removeEventListener("click", fechar);
  }, [menu]);

  const aulaEscolhida = useMemo(() => {
    if (escolhido?.tipo !== "aula") return null;
    for (const [indice, modulo] of lista.entries()) {
      const posicao = modulo.aulas.findIndex((a) => a.id === escolhido.id);
      if (posicao >= 0) return { aula: modulo.aulas[posicao], modulo, numero: indice + 1, posicao: posicao + 1 };
    }
    return null;
  }, [escolhido, lista]);

  const moduloEscolhido = useMemo(() => {
    if (escolhido?.tipo !== "modulo") return null;
    const indice = lista.findIndex((m) => m.id === escolhido.id);
    return indice >= 0 ? { modulo: lista[indice], numero: indice + 1 } : null;
  }, [escolhido, lista]);

  const novoModulo = async () => {
    setCriando("modulo");
    try {
      const resposta = await pedirDigitais<{ id: string }>(`/api/digitais/cursos/${cursoId}/modulos`, { method: "POST", body: "{}" });
      await aoMudar();
      setEscolhido({ tipo: "modulo", id: resposta.id });
    } catch (e) {
      aoAvisar("ruim", e instanceof Error ? e.message : "Não foi possível criar o módulo.");
    } finally {
      setCriando(null);
    }
  };

  const novaAula = async (moduloId: string) => {
    setCriando(moduloId);
    try {
      const resposta = await pedirDigitais<{ id: string }>(`/api/digitais/cursos/${cursoId}/aulas`, {
        method: "POST",
        body: JSON.stringify({ moduloId }),
      });
      await aoMudar();
      setEscolhido({ tipo: "aula", id: resposta.id });
    } catch (e) {
      aoAvisar("ruim", e instanceof Error ? e.message : "Não foi possível criar o vídeo.");
    } finally {
      setCriando(null);
    }
  };

  const ordenarModulos = async (ids: string[]) => {
    setLista((atual) => ids.map((id) => atual.find((m) => m.id === id)).filter((m): m is Modulo => Boolean(m)));
    try {
      await pedirDigitais(`/api/digitais/cursos/${cursoId}/modulos`, { method: "PUT", body: JSON.stringify({ ids }) });
    } catch (e) {
      aoAvisar("ruim", e instanceof Error ? e.message : "Não foi possível salvar a ordem.");
    }
    await aoMudar();
  };

  const ordenarAulas = async (moduloId: string, ids: string[]) => {
    setLista((atual) => {
      const todas = atual.flatMap((m) => m.aulas);
      return atual.map((m) => {
        if (m.id === moduloId) return { ...m, aulas: ids.map((id) => todas.find((a) => a.id === id)).filter((a): a is Aula => Boolean(a)).map((a) => ({ ...a, moduloId })) };
        return { ...m, aulas: m.aulas.filter((a) => !ids.includes(a.id)) };
      });
    });
    try {
      await pedirDigitais(`/api/digitais/cursos/${cursoId}/aulas`, { method: "PUT", body: JSON.stringify({ moduloId, ids }) });
    } catch (e) {
      aoAvisar("ruim", e instanceof Error ? e.message : "Não foi possível salvar a ordem.");
    }
    await aoMudar();
  };

  const moverModulo = (moduloId: string, passo: -1 | 1) => {
    const ids = lista.map((m) => m.id);
    const de = ids.indexOf(moduloId);
    const para = de + passo;
    if (de < 0 || para < 0 || para >= ids.length) return;
    [ids[de], ids[para]] = [ids[para], ids[de]];
    void ordenarModulos(ids);
  };

  const moverAula = (aula: Aula, passo: -1 | 1) => {
    const modulo = lista.find((m) => m.id === aula.moduloId);
    if (!modulo) return;
    const ids = modulo.aulas.map((a) => a.id);
    const de = ids.indexOf(aula.id);
    const para = de + passo;
    if (para < 0 || para >= ids.length) {
      /* Passou da ponta: vai para o módulo vizinho. */
      const indice = lista.findIndex((m) => m.id === modulo.id);
      const vizinho = lista[indice + passo];
      if (!vizinho) return;
      const destino = vizinho.aulas.map((a) => a.id);
      if (passo === -1) destino.push(aula.id);
      else destino.unshift(aula.id);
      void ordenarAulas(vizinho.id, destino);
      return;
    }
    [ids[de], ids[para]] = [ids[para], ids[de]];
    void ordenarAulas(modulo.id, ids);
  };

  const soltar = () => {
    const quem = arrastando;
    const onde = alvo;
    setArrastando(null);
    setAlvo(null);
    if (!quem || !onde) return;
    if (quem.tipo === "modulo") {
      const ids = lista.map((m) => m.id).filter((id) => id !== quem.moduloId);
      const posicao = ids.indexOf(onde.moduloId);
      ids.splice(posicao < 0 ? ids.length : posicao, 0, quem.moduloId);
      if (ids.join() !== lista.map((m) => m.id).join()) void ordenarModulos(ids);
      return;
    }
    const destino = lista.find((m) => m.id === onde.moduloId);
    if (!destino) return;
    const ids = destino.aulas.map((a) => a.id).filter((id) => id !== quem.aulaId);
    const posicao = onde.antesDe ? ids.indexOf(onde.antesDe) : -1;
    ids.splice(posicao < 0 ? ids.length : posicao, 0, quem.aulaId);
    if (destino.id !== quem.moduloId || ids.join() !== destino.aulas.map((a) => a.id).join()) void ordenarAulas(destino.id, ids);
  };

  const enviarVideo = useCallback(
    async (aulaId: string, arquivo: File) => {
      setEnvios((atual) => ({ ...atual, [aulaId]: { enviados: 0, total: arquivo.size, fase: "enviando", nome: arquivo.name } }));
      try {
        const medida = await medirVideo(arquivo);
        await enviarArquivo(
          arquivo,
          (progresso) => {
            if (vivo.current) setEnvios((atual) => ({ ...atual, [aulaId]: { ...progresso, nome: arquivo.name } }));
          },
          new AbortController().signal,
          (arquivoId) => {
            /* A aula aponta para o vídeo assim que o envio abre. */
            void pedirDigitais(`/api/digitais/cursos/${cursoId}/aulas/${aulaId}`, {
              method: "PUT",
              body: JSON.stringify({ videoArquivoId: arquivoId, ...(medida.duracao ? { duracaoS: Math.round(medida.duracao) } : {}) }),
            }).catch(() => undefined);
          }
        );
        aoAvisar("bom", `O vídeo "${arquivo.name}" chegou e já está pronto.`);
      } catch (e) {
        aoAvisar("ruim", e instanceof Error ? e.message : "O envio do vídeo não deu certo.");
      } finally {
        if (vivo.current) {
          setEnvios((atual) => {
            const proximo = { ...atual };
            delete proximo[aulaId];
            return proximo;
          });
        }
        await aoMudar();
      }
    },
    [cursoId, aoAvisar, aoMudar]
  );

  const apagarAula = (aula: Aula) =>
    aoConfirmar({
      titulo: `Apagar o vídeo "${aula.titulo}"?`,
      texto: "Ele some da área dos clientes. O arquivo continua na sua biblioteca.",
      confirmar: "Apagar",
      tom: "perigo",
      aoConfirmar: async () => {
        try {
          await pedirDigitais(`/api/digitais/cursos/${cursoId}/aulas/${aula.id}`, { method: "DELETE" });
          setEscolhido(null);
          await aoMudar();
        } catch (e) {
          aoAvisar("ruim", e instanceof Error ? e.message : "Não foi possível apagar o vídeo.");
        }
      },
    });

  const apagarModulo = (modulo: Modulo) =>
    aoConfirmar({
      titulo: `Apagar o módulo "${modulo.titulo}"?`,
      texto: modulo.aulas.length
        ? `Os ${modulo.aulas.length} vídeos dele somem da área dos clientes. Os arquivos continuam na sua biblioteca.`
        : "Ele está vazio.",
      confirmar: "Apagar",
      tom: "perigo",
      aoConfirmar: async () => {
        try {
          await pedirDigitais(`/api/digitais/cursos/${cursoId}/modulos/${modulo.id}`, { method: "DELETE" });
          setEscolhido(null);
          await aoMudar();
        } catch (e) {
          aoAvisar("ruim", e instanceof Error ? e.message : "Não foi possível apagar o módulo.");
        }
      },
    });

  return (
    <div className="grid gap-5 xl:grid-cols-[minmax(0,420px)_minmax(0,1fr)] xl:items-start">
      <section className="rounded-2xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-elevated)] p-3 shadow-[var(--ks-shadow-subtle)] sm:p-4">
        {lista.length === 0 ? (
          <p className="px-2 py-6 text-center text-sm text-[var(--ks-color-text-muted)]">Comece criando o primeiro módulo.</p>
        ) : null}
        {lista.map((modulo, indice) => {
          const duracao = modulo.aulas.reduce((soma, a) => soma + (a.tipo === "video" ? a.duracaoS ?? 0 : 0), 0);
          const regra = rotuloDaRegra({ liberacao: modulo.liberacao, dias: modulo.liberarDias, em: modulo.liberarEm });
          const moduloAtivo = escolhido?.tipo === "modulo" && escolhido.id === modulo.id;
          return (
            <div
              key={modulo.id}
              className={`border-t border-[var(--ks-n-100)] py-2 first:border-t-0 ${alvo?.moduloId === modulo.id && arrastando?.tipo === "modulo" ? "border-t-2 border-t-[var(--ks-brand-500)]" : ""}`}
              onDragOver={(e) => {
                if (!arrastando) return;
                e.preventDefault();
                if (arrastando.tipo === "modulo") setAlvo({ moduloId: modulo.id, antesDe: null });
                else if (!modulo.aulas.length || alvo?.moduloId !== modulo.id) setAlvo({ moduloId: modulo.id, antesDe: null });
              }}
              onDrop={(e) => {
                e.preventDefault();
                soltar();
              }}
            >
              <div
                className={`group flex items-center gap-1.5 rounded-xl px-1.5 py-1.5 ${moduloAtivo ? "bg-[var(--ks-brand-50)]" : "hover:bg-[var(--ks-color-bg-hover)]"}`}
                draggable={podeEditar}
                onDragStart={(e) => {
                  e.dataTransfer.effectAllowed = "move";
                  e.dataTransfer.setData("text/plain", modulo.id);
                  setArrastando({ tipo: "modulo", moduloId: modulo.id });
                }}
                onDragEnd={() => {
                  setArrastando(null);
                  setAlvo(null);
                }}
              >
                {podeEditar ? <GripVertical size={15} className="shrink-0 cursor-grab text-[var(--ks-color-text-soft)]" /> : null}
                <button type="button" onClick={() => setEscolhido({ tipo: "modulo", id: modulo.id })} className="min-w-0 flex-1 text-left">
                  <span className="block truncate text-sm font-extrabold text-[var(--ks-color-text-primary)]">
                    {indice + 1}. {modulo.titulo}
                    <span className="ml-1.5 text-xs font-normal text-[var(--ks-color-text-muted)]">
                      · {modulo.aulas.length} {modulo.aulas.length === 1 ? "vídeo" : "vídeos"}
                      {duracao ? ` · ${duracaoLegivel(duracao)}` : ""}
                    </span>
                  </span>
                  {regra ? (
                    <span className="mt-0.5 flex items-center gap-1 text-xs font-semibold text-[#b45309]">
                      <Lock size={11} />
                      {regra}
                    </span>
                  ) : null}
                </button>
                {podeEditar ? (
                  <span className="relative">
                    <button
                      type="button"
                      aria-label={`Mais ações do módulo ${modulo.titulo}`}
                      onClick={(e) => {
                        e.stopPropagation();
                        setMenu(menu === modulo.id ? null : modulo.id);
                      }}
                      className="rounded-lg p-1 text-[var(--ks-color-text-soft)] hover:bg-white"
                    >
                      <MoreHorizontal size={16} />
                    </button>
                    {menu === modulo.id ? (
                      <span className="absolute right-0 top-8 z-20 flex w-44 flex-col rounded-xl border border-[var(--ks-color-border-subtle)] bg-white p-1 shadow-lg">
                        <button type="button" className="flex items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-sm hover:bg-[var(--ks-color-bg-hover)]" onClick={() => moverModulo(modulo.id, -1)}>
                          <ArrowUp size={14} />
                          Mover para cima
                        </button>
                        <button type="button" className="flex items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-sm hover:bg-[var(--ks-color-bg-hover)]" onClick={() => moverModulo(modulo.id, 1)}>
                          <ArrowDown size={14} />
                          Mover para baixo
                        </button>
                        <button type="button" className="rounded-lg px-2.5 py-1.5 text-left text-sm text-[#c2263f] hover:bg-[var(--ks-color-bg-hover)]" onClick={() => apagarModulo(modulo)}>
                          Apagar módulo
                        </button>
                      </span>
                    ) : null}
                  </span>
                ) : null}
              </div>

              <ul className="mt-0.5">
                {modulo.aulas.map((aula) => {
                  const Icone = ICONE[aula.tipo];
                  const ativa = escolhido?.tipo === "aula" && escolhido.id === aula.id;
                  const envio = envios[aula.id];
                  const linhaDeSoltura = alvo?.moduloId === modulo.id && alvo.antesDe === aula.id && arrastando?.tipo === "aula";
                  return (
                    <li
                      key={aula.id}
                      className={linhaDeSoltura ? "border-t-2 border-[var(--ks-brand-500)]" : ""}
                      draggable={podeEditar}
                      onDragStart={(e) => {
                        e.stopPropagation();
                        e.dataTransfer.effectAllowed = "move";
                        e.dataTransfer.setData("text/plain", aula.id);
                        setArrastando({ tipo: "aula", aulaId: aula.id, moduloId: modulo.id });
                      }}
                      onDragOver={(e) => {
                        if (arrastando?.tipo !== "aula") return;
                        e.preventDefault();
                        e.stopPropagation();
                        setAlvo({ moduloId: modulo.id, antesDe: aula.id });
                      }}
                      onDrop={(e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        soltar();
                      }}
                      onDragEnd={() => {
                        setArrastando(null);
                        setAlvo(null);
                      }}
                    >
                      <div
                        className={`group flex items-center gap-1.5 rounded-xl px-1.5 py-1.5 ${
                          ativa ? "bg-[var(--ks-brand-50)] shadow-[inset_3px_0_0_var(--ks-brand-600)]" : "hover:bg-[var(--ks-color-bg-hover)]"
                        }`}
                      >
                        {podeEditar ? <GripVertical size={14} className="shrink-0 cursor-grab text-[var(--ks-color-text-soft)]" /> : <span className="w-[14px]" />}
                        <button type="button" onClick={() => setEscolhido({ tipo: "aula", id: aula.id })} className="flex min-w-0 flex-1 items-center gap-2 text-left">
                          <span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-[var(--ks-color-bg-inset)] text-[var(--ks-color-text-secondary)]">
                            <Icone size={12} />
                          </span>
                          <span className={`min-w-0 flex-1 truncate text-sm ${ativa ? "font-bold text-[var(--ks-brand-700)]" : "text-[var(--ks-color-text-primary)]"}`}>
                            {aula.titulo}
                          </span>
                          {!aula.publicada ? (
                            <span className="shrink-0 rounded-full bg-[var(--ks-color-bg-inset)] px-2 py-0.5 text-[10px] font-bold text-[var(--ks-color-text-muted)]">rascunho</span>
                          ) : aula.previaGratis ? (
                            <span className="shrink-0 rounded-full bg-[var(--ks-brand-50)] px-2 py-0.5 text-[10px] font-bold text-[var(--ks-brand-600)]">Prévia grátis</span>
                          ) : null}
                          <span className="ks-num shrink-0 text-xs text-[var(--ks-color-text-muted)]">
                            {envio
                              ? `${Math.round((envio.enviados / Math.max(1, envio.total)) * 100)}%`
                              : aula.tipo === "video"
                                ? aula.duracaoS
                                  ? relogio(aula.duracaoS)
                                  : aula.video || aula.link
                                    ? "—"
                                    : "sem vídeo"
                                : aula.tipo === "texto"
                                  ? "texto"
                                  : aula.tipo === "materiais"
                                    ? `${aula.materiais.length} mat.`
                                    : "ao vivo"}
                          </span>
                        </button>
                        {podeEditar ? (
                          <span className="relative">
                            <button
                              type="button"
                              aria-label={`Mais ações do vídeo ${aula.titulo}`}
                              onClick={(e) => {
                                e.stopPropagation();
                                setMenu(menu === aula.id ? null : aula.id);
                              }}
                              className="rounded-lg p-1 text-[var(--ks-color-text-soft)] opacity-60 hover:bg-white group-hover:opacity-100"
                            >
                              <MoreHorizontal size={15} />
                            </button>
                            {menu === aula.id ? (
                              <span className="absolute right-0 top-7 z-20 flex w-44 flex-col rounded-xl border border-[var(--ks-color-border-subtle)] bg-white p-1 shadow-lg">
                                <button type="button" className="flex items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-sm hover:bg-[var(--ks-color-bg-hover)]" onClick={() => moverAula(aula, -1)}>
                                  <ArrowUp size={14} />
                                  Mover para cima
                                </button>
                                <button type="button" className="flex items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-sm hover:bg-[var(--ks-color-bg-hover)]" onClick={() => moverAula(aula, 1)}>
                                  <ArrowDown size={14} />
                                  Mover para baixo
                                </button>
                                <button type="button" className="rounded-lg px-2.5 py-1.5 text-left text-sm text-[#c2263f] hover:bg-[var(--ks-color-bg-hover)]" onClick={() => apagarAula(aula)}>
                                  Apagar vídeo
                                </button>
                              </span>
                            ) : null}
                          </span>
                        ) : null}
                      </div>
                    </li>
                  );
                })}
              </ul>
              {podeEditar ? (
                <button
                  type="button"
                  onClick={() => void novaAula(modulo.id)}
                  disabled={Boolean(criando)}
                  className="ml-8 mt-1 inline-flex items-center gap-1 text-xs font-semibold text-[var(--ks-brand-600)] hover:underline disabled:opacity-50"
                >
                  <Plus size={13} />
                  Vídeo neste módulo
                </button>
              ) : null}
            </div>
          );
        })}
        {podeEditar ? (
          <button
            type="button"
            onClick={() => void novoModulo()}
            disabled={Boolean(criando)}
            className="mt-2 flex w-full items-center justify-center gap-1.5 rounded-xl border-2 border-dashed border-[var(--ks-brand-200,#ddd6fe)] bg-[var(--ks-brand-50)] py-3 text-sm font-bold text-[var(--ks-brand-600)] disabled:opacity-60"
          >
            <Plus size={15} />
            Novo módulo
          </button>
        ) : null}
      </section>

      <div className="min-w-0">
        {aulaEscolhida ? (
          <EditorDaAula
            key={aulaEscolhida.aula.id}
            cursoId={cursoId}
            aula={aulaEscolhida.aula}
            modulo={{ titulo: aulaEscolhida.modulo.titulo, numero: aulaEscolhida.numero, total: aulaEscolhida.modulo.aulas.length }}
            posicao={aulaEscolhida.posicao}
            podeEditar={podeEditar}
            envio={envios[aulaEscolhida.aula.id] ?? null}
            aoEnviarVideo={(arquivo) => void enviarVideo(aulaEscolhida.aula.id, arquivo)}
            aoMudar={() => void aoMudar()}
            aoAvisar={aoAvisar}
            aoApagar={() => apagarAula(aulaEscolhida.aula)}
          />
        ) : moduloEscolhido ? (
          <EditorDoModulo
            key={moduloEscolhido.modulo.id}
            cursoId={cursoId}
            modulo={moduloEscolhido.modulo}
            numero={moduloEscolhido.numero}
            podeEditar={podeEditar}
            aoMudar={() => void aoMudar()}
            aoAvisar={aoAvisar}
            aoApagar={() => apagarModulo(moduloEscolhido.modulo)}
          />
        ) : (
          <section className="rounded-2xl border border-dashed border-[var(--ks-color-border-strong)] p-10 text-center text-sm text-[var(--ks-color-text-muted)]">
            Escolha um vídeo ou um módulo à esquerda para editar.
          </section>
        )}
      </div>
    </div>
  );
}
