"use client";

import Link from "next/link";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Ban, CalendarClock, Download, Loader2, Plus, RotateCcw, Search, UserPlus, X } from "lucide-react";

import { AreaFechada, CarregandoArea, ErroDaArea, FalhaDaArea, pedirDigitais } from "@/components/digitais/comum";
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";

type Situacao = "ativo" | "preparando" | "bloqueado" | "suspenso" | "vencido" | "cancelado";

type Aluno = {
  chave: string;
  clienteId: string;
  nome: string;
  email: string | null;
  produtoId: string;
  produto: string;
  imagem: string | null;
  tipo: string;
  origem: "pedido" | "cortesia";
  situacao: Situacao;
  liberadoEm: string | null;
  expiraEm: string | null;
  ultimoAcessoEm: string | null;
  downloads: number;
  itens: number;
  pedido: { id: string; numero: number | null } | null;
  /* Só nos cursos. */
  progresso?: number | null;
  certificado?: { codigo: string; emitidoEm: string } | null;
  lembreteEm?: string | null;
};

type Resposta = { podeEditar: boolean; alunos: Aluno[]; produtos: Array<{ id: string; nome: string }> };

type Filtro = "todos" | "com_acesso" | "estudando" | "concluiram" | "parados" | "bloqueados" | "vencidos";

const TRINTA_DIAS = 30 * 24 * 60 * 60 * 1000;

/* Onde o aluno de curso está: concluiu, estudando ou parado há 30 dias (null: não é curso ou não tem acesso). */
function momentoDoCurso(aluno: Aluno, agora = Date.now()): "concluiu" | "estudando" | "parado" | null {
  if (aluno.tipo !== "curso") return null;
  if (aluno.certificado || (aluno.progresso ?? 0) >= 100) return "concluiu";
  if (aluno.situacao !== "ativo") return null;
  const ultimo = new Date(aluno.ultimoAcessoEm || aluno.liberadoEm || 0).getTime();
  return Number.isFinite(ultimo) && agora - ultimo > TRINTA_DIAS ? "parado" : "estudando";
}

function noFiltro(aluno: Aluno, filtro: Filtro): boolean {
  if (filtro === "com_acesso") return aluno.situacao === "ativo" || aluno.situacao === "preparando";
  if (filtro === "estudando") return momentoDoCurso(aluno) === "estudando";
  if (filtro === "concluiram") return momentoDoCurso(aluno) === "concluiu";
  if (filtro === "parados") return momentoDoCurso(aluno) === "parado";
  if (filtro === "bloqueados") return aluno.situacao === "bloqueado" || aluno.situacao === "suspenso";
  if (filtro === "vencidos") return aluno.situacao === "vencido";
  return true;
}

/* A nota embaixo do acesso, como na prévia: certificado, lembrete, cortesia ou a compra. */
function notaDoAluno(aluno: Aluno): string {
  if (aluno.certificado) return "certificado emitido";
  if (aluno.lembreteEm && momentoDoCurso(aluno) === "parado") return "parado: lembrete enviado";
  if (aluno.origem === "cortesia") return "acesso dado por você";
  if (aluno.pedido?.numero) return `pedido #${aluno.pedido.numero}${aluno.liberadoEm ? ` · comprou em ${data(aluno.liberadoEm)}` : ""}`;
  return aluno.liberadoEm ? `desde ${data(aluno.liberadoEm)}` : "—";
}

/* A lista que está na tela, numa planilha (abre no Excel e no Google Planilhas). */
function exportarLista(alunos: Aluno[]) {
  const celula = (valor: string | number | null | undefined) => {
    const texto = String(valor ?? "");
    return /[";\n]/.test(texto) ? `"${texto.replace(/"/g, '""')}"` : texto;
  };
  const linhas = [
    ["Nome", "E-mail", "Produto", "Situação", "Progresso", "Último acesso", "Liberado em", "Acesso até", "Origem", "Pedido", "Certificado"],
    ...alunos.map((a) => [
      a.nome,
      a.email ?? "",
      a.produto,
      SELO[a.situacao].texto,
      a.tipo === "curso" ? `${a.progresso ?? 0}%` : `${a.downloads} downloads`,
      a.ultimoAcessoEm ? new Date(a.ultimoAcessoEm).toLocaleString("pt-BR") : "",
      data(a.liberadoEm) ?? "",
      a.expiraEm ? data(a.expiraEm) : "sem prazo",
      a.origem === "cortesia" ? "Cortesia" : "Compra",
      a.pedido?.numero ? `#${a.pedido.numero}` : "",
      a.certificado?.codigo ?? "",
    ]),
  ];
  const conteudo = "\uFEFF" + linhas.map((linha) => linha.map(celula).join(";")).join("\r\n");
  const url = URL.createObjectURL(new Blob([conteudo], { type: "text/csv;charset=utf-8" }));
  const link = document.createElement("a");
  link.href = url;
  link.download = `clientes-${new Date().toISOString().slice(0, 10)}.csv`;
  document.body.appendChild(link);
  link.click();
  link.remove();
  window.setTimeout(() => URL.revokeObjectURL(url), 1000);
}

const SELO: Record<Situacao, { texto: string; classe: string }> = {
  ativo: { texto: "Com acesso", classe: "bg-[color:rgba(14,158,112,0.12)] text-[var(--ks-emerald)]" },
  preparando: { texto: "Preparando", classe: "bg-[color:rgba(234,179,8,0.14)] text-[#a16207]" },
  bloqueado: { texto: "Bloqueado", classe: "bg-[color:rgba(225,58,88,0.12)] text-[#c2263f]" },
  suspenso: { texto: "Suspenso", classe: "bg-[color:rgba(225,58,88,0.12)] text-[#c2263f]" },
  vencido: { texto: "Vencido", classe: "bg-[var(--ks-color-bg-inset)] text-[var(--ks-color-text-muted)]" },
  cancelado: { texto: "Cancelado", classe: "bg-[var(--ks-color-bg-inset)] text-[var(--ks-color-text-muted)]" },
};

const data = (iso: string | null) => (iso ? new Date(iso).toLocaleDateString("pt-BR") : null);

function haQuanto(iso: string | null): string {
  if (!iso) return "nunca";
  const minutos = Math.round((Date.now() - new Date(iso).getTime()) / 60000);
  if (minutos < 2) return "agora";
  if (minutos < 60) return `há ${minutos} min`;
  const horas = Math.round(minutos / 60);
  if (horas < 24) return `há ${horas} h`;
  const dias = Math.round(horas / 24);
  return dias === 1 ? "ontem" : `há ${dias} dias`;
}

function iniciais(nome: string) {
  return (
    nome
      .trim()
      .split(/\s+/)
      .filter(Boolean)
      .slice(0, 2)
      .map((p) => p[0]?.toUpperCase())
      .join("") || "?"
  );
}

const CORES = ["#E5484D", "#2F80ED", "#0E9E70", "#F2994A", "#7B61FF", "#D9488F"];

function corDoNome(nome: string) {
  let soma = 0;
  for (const letra of nome) soma = (soma + letra.charCodeAt(0)) % 997;
  return CORES[soma % CORES.length];
}

type ClienteAchado = { id: string; nome: string; email: string | null };

function DarAcesso({
  produtos,
  aoFechar,
  aoDar,
}: {
  produtos: Array<{ id: string; nome: string }>;
  aoFechar: () => void;
  aoDar: (mensagem: string) => void;
}) {
  const [busca, setBusca] = useState("");
  const [achados, setAchados] = useState<ClienteAchado[]>([]);
  const [escolhido, setEscolhido] = useState<ClienteAchado | null>(null);
  const [novo, setNovo] = useState(false);
  const [nome, setNome] = useState("");
  const [email, setEmail] = useState("");
  const [produtoId, setProdutoId] = useState(produtos[0]?.id ?? "");
  const [comPrazo, setComPrazo] = useState(false);
  const [dias, setDias] = useState("30");
  const [avisar, setAvisar] = useState(true);
  const [salvando, setSalvando] = useState(false);
  const [erro, setErro] = useState<string | null>(null);

  useEffect(() => {
    if (escolhido || novo || busca.trim().length < 2) return;
    let cancelado = false;
    const espera = window.setTimeout(() => {
      pedirDigitais<{ clientes: ClienteAchado[] }>(`/api/digitais/alunos/clientes?q=${encodeURIComponent(busca.trim())}`)
        .then((resposta) => {
          if (!cancelado) setAchados(resposta.clientes);
        })
        .catch(() => {
          if (!cancelado) setAchados([]);
        });
    }, 250);
    return () => {
      cancelado = true;
      window.clearTimeout(espera);
    };
  }, [busca, escolhido, novo]);

  const dar = async () => {
    setErro(null);
    if (!produtoId) return setErro("Escolha o produto.");
    if (!escolhido && !novo) return setErro("Escolha a pessoa ou cadastre uma nova.");
    setSalvando(true);
    try {
      const resposta = await pedirDigitais<{ nome: string; criados: number; atualizados: number; avisado: boolean; semEmail: boolean }>(
        "/api/digitais/alunos",
        {
          method: "POST",
          body: JSON.stringify({
            produtoId,
            ...(escolhido ? { clienteId: escolhido.id } : { nome, email }),
            prazoDias: comPrazo ? Number(dias) : null,
            avisar,
          }),
        }
      );
      const quem = resposta.nome || "A pessoa";
      aoDar(
        `${quem} ${resposta.atualizados && !resposta.criados ? "teve o prazo do acesso atualizado" : "ganhou o acesso"}.${
          resposta.avisado ? " O aviso por e-mail está saindo." : resposta.semEmail ? " O cadastro não tem e-mail: avise a pessoa por outro caminho." : ""
        }`
      );
    } catch (e) {
      setErro(e instanceof Error ? e.message : "Não foi possível dar o acesso.");
      setSalvando(false);
    }
  };

  const campo =
    "h-10 w-full rounded-xl border border-[var(--ks-color-border-subtle)] bg-white px-3 text-sm text-[var(--ks-color-text-primary)] outline-none focus:border-[var(--ks-brand-500)]";

  return (
    <section className="rounded-2xl border border-[var(--ks-brand-200,#ddd6fe)] bg-[var(--ks-color-bg-elevated)] p-5 shadow-[var(--ks-shadow-subtle)] sm:p-6">
      <div className="flex items-start justify-between gap-3">
        <div>
          <h2 className="text-[17px] font-extrabold text-[var(--ks-color-text-primary)]">Dar acesso</h2>
          <p className="mt-0.5 text-[13px] text-[var(--ks-color-text-muted)]">
            Cortesia, parceria ou compra fora da loja. A pessoa entra em Minhas compras com o e-mail dela.
          </p>
        </div>
        <button type="button" onClick={aoFechar} className="rounded-lg p-1.5 text-[var(--ks-color-text-muted)] hover:bg-[var(--ks-color-bg-hover)]" aria-label="Fechar">
          <X size={18} />
        </button>
      </div>

      {erro ? (
        <div className="mt-3">
          <Aviso tom="ruim" aoFechar={() => setErro(null)}>
            {erro}
          </Aviso>
        </div>
      ) : null}

      <div className="mt-4 grid gap-4 lg:grid-cols-2">
        <div>
          <p className="mb-1.5 text-xs font-bold text-[var(--ks-color-text-secondary)]">Pessoa</p>
          {escolhido ? (
            <div className="flex items-center justify-between gap-3 rounded-xl border border-[var(--ks-color-border-subtle)] px-3 py-2">
              <span className="min-w-0">
                <span className="block truncate text-sm font-bold text-[var(--ks-color-text-primary)]">{escolhido.nome}</span>
                <span className="block truncate text-xs text-[var(--ks-color-text-muted)]">{escolhido.email || "sem e-mail no cadastro"}</span>
              </span>
              <button type="button" className="text-xs font-semibold text-[var(--ks-brand-600)]" onClick={() => setEscolhido(null)}>
                Trocar
              </button>
            </div>
          ) : novo ? (
            <div className="space-y-2">
              <input className={campo} placeholder="Nome completo" value={nome} onChange={(e) => setNome(e.target.value)} maxLength={120} />
              <input className={campo} placeholder="E-mail (é por ele que a pessoa entra)" value={email} onChange={(e) => setEmail(e.target.value)} type="email" maxLength={254} />
              <button type="button" className="text-xs font-semibold text-[var(--ks-brand-600)]" onClick={() => setNovo(false)}>
                Procurar um cliente que já existe
              </button>
            </div>
          ) : (
            <div>
              <div className="relative">
                <Search size={15} className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[var(--ks-color-text-soft)]" />
                <input className={`${campo} pl-9`} placeholder="Nome, e-mail ou CPF do cliente" value={busca} onChange={(e) => setBusca(e.target.value)} />
              </div>
              {busca.trim().length >= 2 && achados.length ? (
                <ul className="mt-2 overflow-hidden rounded-xl border border-[var(--ks-color-border-subtle)]">
                  {achados.map((cliente) => (
                    <li key={cliente.id}>
                      <button
                        type="button"
                        onClick={() => setEscolhido(cliente)}
                        className="flex w-full items-center justify-between gap-3 px-3 py-2 text-left hover:bg-[var(--ks-color-bg-hover)]"
                      >
                        <span className="min-w-0">
                          <span className="block truncate text-sm font-semibold text-[var(--ks-color-text-primary)]">{cliente.nome}</span>
                          <span className="block truncate text-xs text-[var(--ks-color-text-muted)]">{cliente.email || "sem e-mail"}</span>
                        </span>
                      </button>
                    </li>
                  ))}
                </ul>
              ) : null}
              <button type="button" className="mt-2 inline-flex items-center gap-1.5 text-xs font-semibold text-[var(--ks-brand-600)]" onClick={() => setNovo(true)}>
                <UserPlus size={14} />
                Cadastrar uma pessoa nova
              </button>
            </div>
          )}
        </div>

        <div className="space-y-4">
          <div>
            <p className="mb-1.5 text-xs font-bold text-[var(--ks-color-text-secondary)]">Produto</p>
            <select className={campo} value={produtoId} onChange={(e) => setProdutoId(e.target.value)}>
              {produtos.map((produto) => (
                <option key={produto.id} value={produto.id}>
                  {produto.nome}
                </option>
              ))}
            </select>
          </div>
          <div>
            <p className="mb-1.5 text-xs font-bold text-[var(--ks-color-text-secondary)]">Por quanto tempo</p>
            <div className="flex flex-wrap items-center gap-4 text-sm text-[var(--ks-color-text-primary)]">
              <label className="inline-flex items-center gap-2">
                <input type="radio" checked={!comPrazo} onChange={() => setComPrazo(false)} className="accent-[var(--ks-brand-600)]" />
                Para sempre
              </label>
              <label className="inline-flex items-center gap-2">
                <input type="radio" checked={comPrazo} onChange={() => setComPrazo(true)} className="accent-[var(--ks-brand-600)]" />
                Por
                <input
                  className="h-9 w-20 rounded-lg border border-[var(--ks-color-border-subtle)] px-2 text-sm"
                  inputMode="numeric"
                  value={dias}
                  onChange={(e) => setDias(e.target.value.replace(/\D/g, "").slice(0, 4))}
                  onFocus={() => setComPrazo(true)}
                />
                dias
              </label>
            </div>
          </div>
          <label className="inline-flex items-center gap-2 text-sm text-[var(--ks-color-text-primary)]">
            <input type="checkbox" checked={avisar} onChange={(e) => setAvisar(e.target.checked)} className="accent-[var(--ks-brand-600)]" />
            Avisar a pessoa por e-mail
          </label>
        </div>
      </div>

      <div className="mt-5 flex flex-wrap justify-end gap-2">
        <button type="button" onClick={aoFechar} className="ks-button ks-button-soft" disabled={salvando}>
          Cancelar
        </button>
        <button type="button" onClick={() => void dar()} className="ks-button ks-button-primary" disabled={salvando}>
          {salvando ? <Loader2 size={16} className="animate-spin" /> : null}
          Dar acesso
        </button>
      </div>
    </section>
  );
}

export default function AlunosEAcessos() {
  const [dados, setDados] = useState<Resposta | null>(null);
  const [erro, setErro] = useState<Error | null>(null);
  const [filtro, setFiltro] = useState<Filtro>("todos");
  const [busca, setBusca] = useState("");
  const [dando, setDando] = useState(false);
  const [aviso, setAviso] = useState<{ tom: "bom" | "ruim"; texto: string } | null>(null);
  const [confirmacao, setConfirmacao] = useState<Confirmacao | null>(null);
  const [ocupado, setOcupado] = useState<string | null>(null);
  const [prazoDe, setPrazoDe] = useState<{ aluno: Aluno; dias: string; sempre: boolean } | null>(null);

  const carregar = useCallback(
    () =>
      pedirDigitais<Resposta>("/api/digitais/alunos")
        .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]);

  /* Com curso na lista, os filtros falam de estudo (como na prévia); sem curso, de acesso. */
  const temCurso = useMemo(() => (dados?.alunos ?? []).some((a) => a.tipo === "curso"), [dados]);
  const filtros: Array<{ valor: Filtro; rotulo: string }> = [
    { valor: "todos", rotulo: "Todos" },
    ...(temCurso
      ? [
          { valor: "estudando" as const, rotulo: "Assistindo" },
          { valor: "concluiram" as const, rotulo: "Concluíram" },
          { valor: "parados" as const, rotulo: "Parados há 30 dias" },
        ]
      : [{ valor: "com_acesso" as const, rotulo: "Com acesso" }]),
    { valor: "bloqueados", rotulo: "Bloqueados" },
    { valor: "vencidos", rotulo: "Acesso vencido" },
  ];

  const contagem = useMemo(() => {
    const lista = dados?.alunos ?? [];
    const conta = (f: Filtro) => lista.filter((a) => noFiltro(a, f)).length;
    return {
      todos: lista.length,
      com_acesso: conta("com_acesso"),
      estudando: conta("estudando"),
      concluiram: conta("concluiram"),
      parados: conta("parados"),
      bloqueados: conta("bloqueados"),
      vencidos: conta("vencidos"),
    } satisfies Record<Filtro, number>;
  }, [dados]);

  const visiveis = useMemo(() => {
    const termo = busca.trim().toLowerCase();
    return (dados?.alunos ?? [])
      .filter((a) => noFiltro(a, filtro))
      .filter((a) => !termo || `${a.nome} ${a.email ?? ""} ${a.produto}`.toLowerCase().includes(termo));
  }, [dados, filtro, busca]);

  const mexer = async (aluno: Aluno, acao: "bloquear" | "reativar" | "prazo", prazoDias?: number | null) => {
    setOcupado(aluno.chave);
    try {
      await pedirDigitais("/api/digitais/alunos", {
        method: "PATCH",
        body: JSON.stringify({ clienteId: aluno.clienteId, produtoId: aluno.produtoId, acao, prazoDias }),
      });
      setAviso({
        tom: "bom",
        texto:
          acao === "bloquear"
            ? `${aluno.nome} não acessa mais ${aluno.produto}.`
            : acao === "reativar"
              ? `${aluno.nome} voltou a acessar ${aluno.produto}.`
              : `O prazo de ${aluno.nome} foi atualizado.`,
      });
      await carregar();
    } catch (e) {
      setAviso({ tom: "ruim", texto: e instanceof Error ? e.message : "Não foi possível salvar." });
    } finally {
      setOcupado(null);
      setConfirmacao(null);
      setPrazoDe(null);
    }
  };

  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 />;

  return (
    <div className="space-y-5">
      <PageHeader
        eyebrow="Quem comprou"
        title="Clientes e acessos"
        subtitle="Quem tem acesso a cada produto, até quando, e o que já baixou."
        actions={
          <span className="flex flex-wrap gap-2">
            {visiveis.length ? (
              <button type="button" onClick={() => exportarLista(visiveis)} className="ks-button ks-button-soft">
                <Download size={16} />
                Exportar lista
              </button>
            ) : null}
            {dados.podeEditar && !dando && dados.produtos.length ? (
              <button type="button" onClick={() => setDando(true)} className="ks-button ks-button-primary">
                <Plus size={16} />
                Dar acesso
              </button>
            ) : null}
          </span>
        }
      />

      {aviso ? (
        <Aviso tom={aviso.tom} aoFechar={() => setAviso(null)}>
          {aviso.texto}
        </Aviso>
      ) : null}

      {dando ? (
        <DarAcesso
          produtos={dados.produtos}
          aoFechar={() => setDando(false)}
          aoDar={(mensagem) => {
            setDando(false);
            setAviso({ tom: "bom", texto: mensagem });
            void carregar();
          }}
        />
      ) : null}

      <div className="flex flex-wrap items-center justify-between gap-3">
        <div className="flex flex-wrap gap-2">
          {filtros.map((f) => {
            const ativo = filtro === f.valor;
            return (
              <button
                key={f.valor}
                type="button"
                onClick={() => setFiltro(f.valor)}
                className={`rounded-full border px-3.5 py-1.5 text-[13px] font-semibold transition-colors ${
                  ativo
                    ? "border-[var(--ks-brand-600)] bg-[var(--ks-brand-600)] text-white"
                    : "border-[var(--ks-color-border-subtle)] bg-white text-[var(--ks-color-text-secondary)] hover:border-[var(--ks-brand-500)]"
                }`}
              >
                {f.rotulo} <span className={`ks-num ml-1 ${ativo ? "text-white/80" : "text-[var(--ks-color-text-soft)]"}`}>{contagem[f.valor]}</span>
              </button>
            );
          })}
        </div>
        <div className="relative w-full sm:w-72">
          <Search size={15} className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[var(--ks-color-text-soft)]" />
          <input
            value={busca}
            onChange={(e) => setBusca(e.target.value)}
            placeholder="Buscar pessoa ou produto"
            className="h-10 w-full rounded-xl border border-[var(--ks-color-border-subtle)] bg-white pl-9 pr-3 text-sm outline-none focus:border-[var(--ks-brand-500)]"
          />
        </div>
      </div>

      <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,1.2fr)_minmax(0,1fr)_100px_120px_150px_minmax(0,0.9fr)] 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)] xl:grid">
          <span>Pessoa</span>
          <span>Produto</span>
          <span>Progresso</span>
          <span>Último acesso</span>
          <span>Acesso</span>
          <span />
        </div>
        {visiveis.length === 0 ? (
          <div className="flex flex-col items-center gap-2 px-6 py-14 text-center">
            <p className="text-sm font-semibold text-[var(--ks-color-text-primary)]">
              {dados.alunos.length === 0 ? "Ninguém tem acesso ainda." : "Ninguém neste filtro."}
            </p>
            {dados.alunos.length === 0 ? (
              <p className="max-w-sm text-xs leading-5 text-[var(--ks-color-text-muted)]">
                Quem comprar um produto digital aparece aqui sozinho, assim que o pagamento for aprovado.
              </p>
            ) : null}
          </div>
        ) : (
          <ul className="px-2 sm:px-3">
            {visiveis.map((aluno) => {
              const selo = SELO[aluno.situacao];
              const podeBloquear = dados.podeEditar && ["ativo", "preparando", "suspenso"].includes(aluno.situacao);
              const podeReativar = dados.podeEditar && ["bloqueado", "suspenso", "vencido"].includes(aluno.situacao);
              return (
                <li key={aluno.chave} className={FIO_DA_LINHA}>
                  <div className="grid grid-cols-1 items-center gap-3 rounded-xl px-2 py-3 xl:grid-cols-[minmax(0,1.2fr)_minmax(0,1fr)_100px_120px_150px_minmax(0,0.9fr)] xl:gap-4">
                    <span className="flex min-w-0 items-center gap-3">
                      <span
                        className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-xs font-bold text-white"
                        style={{ backgroundColor: corDoNome(aluno.nome) }}
                      >
                        {iniciais(aluno.nome)}
                      </span>
                      <span className="min-w-0">
                        <span className="block truncate text-sm font-bold text-[var(--ks-color-text-primary)]">{aluno.nome}</span>
                        <span className="block truncate text-xs text-[var(--ks-color-text-muted)]">{aluno.email || "sem e-mail no cadastro"}</span>
                      </span>
                    </span>
                    <span className="min-w-0 truncate text-sm text-[var(--ks-color-text-primary)]">
                      <Link href={`/dashboard/digitais/produtos/${aluno.produtoId}`} className="hover:underline">
                        {aluno.produto}
                      </Link>
                    </span>
                    {aluno.tipo === "curso" ? (
                      <span className="flex items-center gap-2">
                        <span className="h-1.5 w-full max-w-[120px] overflow-hidden rounded-full bg-[var(--ks-color-bg-inset)] xl:max-w-none">
                          <span
                            className="block h-full rounded-full"
                            style={{ width: `${aluno.progresso ?? 0}%`, background: (aluno.progresso ?? 0) >= 100 ? "var(--ks-emerald)" : "var(--ks-brand-600)" }}
                          />
                        </span>
                        <span className="ks-num text-xs text-[var(--ks-color-text-secondary)]">{aluno.progresso ?? 0}%</span>
                      </span>
                    ) : (
                      <span className="ks-num text-sm text-[var(--ks-color-text-primary)]">
                        {aluno.downloads} <span className="text-xs text-[var(--ks-color-text-muted)]">{aluno.downloads === 1 ? "download" : "downloads"}</span>
                      </span>
                    )}
                    <span className="text-sm text-[var(--ks-color-text-secondary)]">
                      <span className="xl:hidden text-xs text-[var(--ks-color-text-muted)]">Último acesso: </span>
                      {haQuanto(aluno.ultimoAcessoEm)}
                    </span>
                    <span className="min-w-0">
                      <span className={`inline-block rounded-full px-2.5 py-0.5 text-xs font-bold ${selo.classe}`}>{selo.texto}</span>
                      <span className="mt-0.5 line-clamp-2 block text-xs text-[var(--ks-color-text-muted)]">
                        {aluno.expiraEm ? `até ${data(aluno.expiraEm)}` : "vitalício"} · {notaDoAluno(aluno)}
                      </span>
                    </span>
                    <span className="flex flex-wrap items-center gap-1.5 xl:justify-end">
                      {ocupado === aluno.chave ? <Loader2 size={16} className="animate-spin text-[var(--ks-color-text-muted)]" /> : null}
                      {dados.podeEditar && aluno.situacao !== "cancelado" ? (
                        <button
                          type="button"
                          disabled={Boolean(ocupado)}
                          onClick={() => setPrazoDe({ aluno, dias: "30", sempre: !aluno.expiraEm })}
                          className="inline-flex h-8 items-center gap-1 rounded-lg px-2.5 text-xs font-semibold text-[var(--ks-color-text-secondary)] hover:bg-[var(--ks-color-bg-hover)]"
                        >
                          <CalendarClock size={14} />
                          Prazo
                        </button>
                      ) : null}
                      {podeReativar ? (
                        <button
                          type="button"
                          disabled={Boolean(ocupado)}
                          onClick={() => void mexer(aluno, "reativar")}
                          className="inline-flex h-8 items-center gap-1 rounded-lg px-2.5 text-xs font-semibold text-[var(--ks-emerald)] hover:bg-[var(--ks-color-bg-hover)]"
                        >
                          <RotateCcw size={14} />
                          Reativar
                        </button>
                      ) : null}
                      {podeBloquear ? (
                        <button
                          type="button"
                          disabled={Boolean(ocupado)}
                          onClick={() =>
                            setConfirmacao({
                              titulo: `Bloquear o acesso de ${aluno.nome}?`,
                              texto: `A pessoa deixa de baixar ${aluno.produto} na hora. Dá para reativar depois.`,
                              confirmar: "Bloquear",
                              tom: "perigo",
                              aoConfirmar: () => mexer(aluno, "bloquear"),
                            })
                          }
                          className="inline-flex h-8 items-center gap-1 rounded-lg px-2.5 text-xs font-semibold text-[#c2263f] hover:bg-[var(--ks-color-bg-hover)]"
                        >
                          <Ban size={14} />
                          Bloquear
                        </button>
                      ) : null}
                    </span>
                  </div>
                  {prazoDe?.aluno.chave === aluno.chave ? (
                    <div className="mx-2 mb-3 flex flex-wrap items-center gap-3 rounded-xl bg-[var(--ks-color-bg-inset)] px-3 py-2.5 text-sm text-[var(--ks-color-text-primary)]">
                      <label className="inline-flex items-center gap-2">
                        <input
                          type="radio"
                          checked={prazoDe.sempre}
                          onChange={() => setPrazoDe({ ...prazoDe, sempre: true })}
                          className="accent-[var(--ks-brand-600)]"
                        />
                        Sem prazo
                      </label>
                      <label className="inline-flex items-center gap-2">
                        <input
                          type="radio"
                          checked={!prazoDe.sempre}
                          onChange={() => setPrazoDe({ ...prazoDe, sempre: false })}
                          className="accent-[var(--ks-brand-600)]"
                        />
                        Mais
                        <input
                          className="h-8 w-16 rounded-lg border border-[var(--ks-color-border-subtle)] bg-white px-2 text-sm"
                          inputMode="numeric"
                          value={prazoDe.dias}
                          onFocus={() => setPrazoDe({ ...prazoDe, sempre: false })}
                          onChange={(e) => setPrazoDe({ ...prazoDe, dias: e.target.value.replace(/\D/g, "").slice(0, 4) })}
                        />
                        dias a partir de hoje
                      </label>
                      <span className="ml-auto flex gap-2">
                        <button type="button" className="ks-button ks-button-soft" onClick={() => setPrazoDe(null)}>
                          Cancelar
                        </button>
                        <button
                          type="button"
                          className="ks-button ks-button-primary"
                          disabled={Boolean(ocupado) || (!prazoDe.sempre && !(Number(prazoDe.dias) > 0))}
                          onClick={() => void mexer(aluno, "prazo", prazoDe.sempre ? null : Number(prazoDe.dias))}
                        >
                          Salvar prazo
                        </button>
                      </span>
                    </div>
                  ) : null}
                </li>
              );
            })}
          </ul>
        )}
      </section>

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