import { darAcessoDeCortesia, listarAcessosDaLoja, mexerNoAcesso } from "@/lib/digitais/servidor/acoes/alunos";
import { comentariosParaResponder } from "@/lib/digitais/servidor/acoes/comentarios";
import { agirNaEntrega, listarEntregasDaLoja, type AcaoNaEntrega } from "@/lib/digitais/servidor/acoes/entregas";
import { apagarComentario, mudarSituacaoDoComentario, responderComentario } from "@/lib/digitais/servidor/comentarios";

import { AVISO_DE_DADOS, contagem, recusar, texto } from "./comum";
import { abrirDigital, arquivoIndicado, naRota, pedidoDoAssistente, semContatoNovo } from "./digitais-comum";
import { dataEHoraBr } from "./digitais-regras";
import type { Ferramenta, FerramentaDeEscrita, FerramentaDeLeitura } from "./tipos";

/*
 * Quem comprou, pelo assistente: Clientes e acessos (dar acesso de cortesia,
 * bloquear, reativar, mudar o prazo; progresso e certificado), Comentários
 * (responder, publicar, ocultar, apagar) e Entregas (reenviar o e-mail,
 * link da entrega, liberar, anexar o arquivo final, reativar). As funções
 * das rotas e as permissões das telas: digital.students.*, digital.comments.*
 * e digital.deliveries.*. O que manda e-mail a cliente passa pela prévia com
 * código, e só onde a tela tem o mesmo botão.
 */

/* ------------------------------------------------------------ acessos */

export const listarAcessos: FerramentaDeLeitura = {
  nome: "listar_acessos",
  titulo: "Ver quem tem acesso aos produtos digitais",
  descricao:
    "Clientes e acessos: cada pessoa em cada produto digital, com a situação (ativo, preparando, bloqueado, suspenso, vencido, cancelado), de onde veio (pedido ou cortesia), até quando vale, último acesso, downloads, quanto assistiu do conteúdo em vídeo e o certificado emitido.",
  campos: {
    produto_id: { tipo: "id", descricao: "Só deste produto." },
    situacao: { tipo: "opcao", descricao: "Só nesta situação.", opcoes: ["ativo", "preparando", "bloqueado", "suspenso", "vencido", "cancelado"] },
    busca: { tipo: "texto", descricao: "Parte do nome ou do e-mail.", max: 80 },
  },
  tipo: "leitura",
  permissoes: ["digital.students.read"],
  async executar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.students.read", "ver os clientes dos produtos digitais");
    const lido = await naRota(() => listarAcessosDaLoja(contexto));
    const busca = String(args.busca ?? "").trim().toLowerCase();
    const acessos = lido.alunos
      .filter((a) => !args.produto_id || a.produtoId === args.produto_id)
      .filter((a) => !args.situacao || a.situacao === args.situacao)
      .filter((a) => !busca || a.nome.toLowerCase().includes(busca) || (a.email ?? "").toLowerCase().includes(busca))
      .slice(0, 200)
      .map((a) => ({
        cliente_id: a.clienteId,
        nome: a.nome,
        email: a.email,
        produto_id: a.produtoId,
        produto: a.produto,
        situacao: a.situacao,
        origem: a.origem,
        liberado_em: dataEHoraBr(a.liberadoEm),
        vale_ate: a.expiraEm ? dataEHoraBr(a.expiraEm) : "sem prazo",
        ultimo_acesso: dataEHoraBr(a.ultimoAcessoEm),
        downloads: a.downloads,
        pedido: a.pedido?.numero ?? null,
        assistido: a.progresso === null ? undefined : `${a.progresso}%`,
        certificado: a.certificado ? { codigo: a.certificado.codigo, emitido_em: dataEHoraBr(a.certificado.emitidoEm) } : undefined,
      }));
    return {
      dados: { _observacao: AVISO_DE_DADOS, acessos, total: acessos.length, produtos: lido.produtos },
      resumo: `Consultou os acessos dos produtos digitais (${acessos.length})`,
    };
  },
};

type CargaDoAcesso = { corpo: Record<string, unknown>; descricao: string };

export const darAcesso: FerramentaDeEscrita<CargaDoAcesso> = {
  nome: "dar_acesso",
  titulo: "Dar acesso de cortesia",
  descricao:
    "Dá acesso de cortesia a um produto digital (como o botão da tela): a um cliente já cadastrado (cliente_id, de buscar_clientes) ou a alguém novo (nome e e-mail; é por esse e-mail que a pessoa entra). Prazo opcional em dias. Com avisar_por_email = true a pessoa recebe o e-mail de acesso — aí pede confirmação.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto digital.", obrigatorio: true },
    cliente_id: { tipo: "id", descricao: "Cliente já cadastrado." },
    nome: { tipo: "texto", descricao: "Ou o nome de quem recebe.", max: 120 },
    email: { tipo: "texto", descricao: "E o e-mail (é por ele que a pessoa entra).", max: 254 },
    prazo_dias: { tipo: "inteiro", descricao: "Dias de acesso (vazio = sem prazo).", min: 1, max: 3650 },
    avisar_por_email: { tipo: "booleano", descricao: "Mandar o e-mail de acesso à pessoa." },
  },
  tipo: "escrita",
  permissoes: ["digital.students.write"],
  sensivel: (args) => args.avisar_por_email === true,
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.students.write", "dar acesso aos produtos digitais");
    if (!args.cliente_id && (!args.nome || !args.email)) recusar("Diga o cliente_id, ou o nome e o e-mail da pessoa.");
    const { data } = await contexto.admin.from("products").select("name").eq("id", String(args.produto_id)).eq("user_id", contexto.lojaId).eq("product_kind", "digital").maybeSingle();
    const produto = (data as { name?: string } | null)?.name;
    if (!produto) recusar("Produto digital não encontrado. Use listar_produtos_digitais.");
    const quem = args.cliente_id ? `cliente ${args.cliente_id}` : `${args.nome} <${args.email}>`;
    return {
      previa: { produto, para: quem, prazo: args.prazo_dias ? `${args.prazo_dias} dias` : "sem prazo", avisar_por_email: args.avisar_por_email === true },
      resumo: `Prévia de acesso de cortesia a ${produto}`,
      avisos: args.avisar_por_email === true ? ["A pessoa recebe o e-mail de acesso, em nome da loja."] : [],
      carga: {
        corpo: { produtoId: args.produto_id, clienteId: args.cliente_id, nome: args.nome, email: args.email, prazoDias: args.prazo_dias, avisar: args.avisar_por_email === true },
        descricao: `${produto} para ${quem}`,
      },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.students.write", "dar acesso aos produtos digitais");
    const feito = await naRota(() => darAcessoDeCortesia(contexto, carga.corpo));
    return {
      dados: {
        cliente_id: feito.clienteId,
        nome: feito.nome,
        itens_liberados: feito.criados,
        prazos_atualizados: feito.atualizados,
        email_enviado: feito.avisado,
        ...(feito.semEmail ? { aviso: "A pessoa não tem e-mail no cadastro: o aviso não saiu." } : {}),
      },
      resumo: `Deu acesso de cortesia: ${carga.descricao}`,
    };
  },
};

export const mudarAcesso: FerramentaDeEscrita<CargaDoAcesso> = {
  nome: "mudar_acesso",
  titulo: "Bloquear, reativar ou mudar o prazo de um acesso",
  descricao:
    "Mexe no acesso de uma pessoa a um produto digital, como a tela: bloquear (tira o acesso; pede confirmação), reativar, ou mudar o prazo (prazo_dias; 0 = sem prazo). Os ids vêm de listar_acessos.",
  campos: {
    cliente_id: { tipo: "id", descricao: "Id do cliente.", obrigatorio: true },
    produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true },
    acao: { tipo: "opcao", descricao: "bloquear, reativar ou prazo.", opcoes: ["bloquear", "reativar", "prazo"], obrigatorio: true },
    prazo_dias: { tipo: "inteiro", descricao: "Com acao = prazo: dias a partir de hoje (0 = sem prazo).", min: 0, max: 3650 },
  },
  tipo: "escrita",
  sobrescreve: true,
  permissoes: ["digital.students.write"],
  sensivel: (args) => args.acao === "bloquear",
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.students.write", "mexer nos acessos dos produtos digitais");
    if (args.acao === "prazo" && args.prazo_dias === undefined) recusar("Diga o prazo em prazo_dias (0 = sem prazo).");
    const lido = await naRota(() => listarAcessosDaLoja(contexto));
    const acesso = lido.alunos.find((a) => a.clienteId === args.cliente_id && a.produtoId === args.produto_id);
    if (!acesso) recusar("Esta pessoa não tem acesso a este produto. Veja listar_acessos.");
    const acao = args.acao === "bloquear" ? "bloquear o acesso" : args.acao === "reativar" ? "reativar o acesso" : `mudar o prazo para ${args.prazo_dias ? `${args.prazo_dias} dias` : "sem prazo"}`;
    return {
      previa: { cliente: acesso.nome, produto: acesso.produto, situacao_atual: acesso.situacao, acao },
      resumo: `Prévia de ${acao} de ${acesso.nome}`,
      avisos: args.acao === "bloquear" ? ["A pessoa deixa de entrar neste produto até ser reativada."] : [],
      carga: {
        corpo: { clienteId: args.cliente_id, produtoId: args.produto_id, acao: args.acao, prazoDias: args.prazo_dias ? args.prazo_dias : null },
        descricao: `${acao} de ${acesso.nome} em ${acesso.produto}`,
      },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.students.write", "mexer nos acessos dos produtos digitais");
    const feito = await naRota(() => mexerNoAcesso(contexto, carga.corpo));
    return { dados: { itens_mexidos: feito.mexidos }, resumo: carga.descricao.charAt(0).toUpperCase() + carga.descricao.slice(1) };
  },
};

/* ------------------------------------------------------------ comentários */

export const listarComentarios: FerramentaDeLeitura = {
  nome: "listar_comentarios",
  titulo: "Ver os comentários dos vídeos",
  descricao:
    "Os comentários dos clientes embaixo dos vídeos dos conteúdos, por conversa (com as respostas): sem resposta (padrão), pendentes (esperando aprovação), todos ou ocultos. Cada um com o comentario_id para responder, publicar, ocultar ou apagar.",
  campos: {
    filtro: { tipo: "opcao", descricao: "sem_resposta, pendentes, todos ou ocultos.", opcoes: ["sem_resposta", "pendentes", "todos", "ocultos"] },
    produto_id: { tipo: "id", descricao: "Só deste conteúdo em vídeo." },
    antes_de: { tipo: "texto", descricao: "Para ver mais antigos: o valor mais_antigos da resposta anterior.", max: 40 },
  },
  tipo: "leitura",
  permissoes: ["digital.comments.read"],
  async executar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.comments.read", "ver os comentários");
    const lido = await naRota(() =>
      comentariosParaResponder(contexto, { filtro: (args.filtro as string | undefined) ?? null, cursoId: (args.produto_id as string | undefined) ?? null, antes: (args.antes_de as string | undefined) ?? null })
    );
    const comentarios = lido.comentarios.map((c) => ({
      comentario_id: c.id,
      cliente: c.aluno?.nome ?? (c.daLoja ? lido.nomeDaLoja : "Cliente"),
      conteudo: c.curso.nome,
      video: c.aula.titulo,
      texto: texto(c.texto, 1500),
      situacao: c.status,
      quando: dataEHoraBr(c.criadoEm),
      respondido: c.respondido,
      respostas: c.respostas.map((r) => ({ comentario_id: r.id, autor: r.autor, da_loja: r.daLoja, texto: texto(r.texto, 1000), situacao: r.status })),
    }));
    return {
      dados: { _observacao: AVISO_DE_DADOS, contagem: { sem_resposta: lido.contagem.semResposta, pendentes: lido.contagem.pendentes }, comentarios, mais_antigos: lido.maisAntigos },
      resumo: `Consultou os comentários (${comentarios.length})`,
    };
  },
};

type CargaDoComentario = { id: string; texto?: string; status?: string; resumo: string };

export const responderComentarioFerramenta: FerramentaDeEscrita<CargaDoComentario> = {
  nome: "responder_comentario",
  titulo: "Responder um comentário",
  descricao: "Responde um comentário de cliente com o nome e o selo da loja (a resposta aparece para os clientes daquele conteúdo). Responder a uma pergunta pendente também a publica.",
  campos: {
    comentario_id: { tipo: "id", descricao: "Id do comentário (de listar_comentarios).", obrigatorio: true },
    texto: { tipo: "texto", descricao: "A resposta.", obrigatorio: true, max: 2000 },
  },
  tipo: "escrita",
  permissoes: ["digital.comments.write"],
  async preparar(ctx, args) {
    await abrirDigital(ctx, "digital.comments.write", "responder comentários");
    semContatoNovo("", String(args.texto), "em Produtos digitais, Comentários");
    return {
      previa: { responder: args.comentario_id, texto: args.texto },
      resumo: "Prévia de resposta a um comentário",
      avisos: [],
      carga: { id: String(args.comentario_id), texto: String(args.texto), resumo: "Respondeu um comentário" },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.comments.write", "responder comentários");
    const feito = await naRota(() => responderComentario(contexto.admin, { lojaId: contexto.lojaId, eu: contexto.user.id, id: carga.id, texto: carga.texto }));
    return { dados: { resposta_id: feito.id }, resumo: carga.resumo };
  },
};

export const mudarComentario: FerramentaDeEscrita<CargaDoComentario> = {
  nome: "mudar_comentario",
  titulo: "Publicar ou ocultar um comentário",
  descricao: "Aprova (publica) um comentário pendente, oculta um comentário ou mostra de novo um oculto.",
  campos: {
    comentario_id: { tipo: "id", descricao: "Id do comentário.", obrigatorio: true },
    situacao: { tipo: "opcao", descricao: "publicado ou oculto.", opcoes: ["publicado", "oculto"], obrigatorio: true },
  },
  tipo: "escrita",
  permissoes: ["digital.comments.write"],
  async preparar(ctx, args) {
    await abrirDigital(ctx, "digital.comments.write", "mudar comentários");
    return {
      previa: { comentario: args.comentario_id, situacao: args.situacao },
      resumo: `Prévia de deixar um comentário ${args.situacao}`,
      avisos: [],
      carga: { id: String(args.comentario_id), status: String(args.situacao), resumo: args.situacao === "publicado" ? "Publicou um comentário" : "Ocultou um comentário" },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.comments.write", "mudar comentários");
    await naRota(() => mudarSituacaoDoComentario(contexto.admin, { lojaId: contexto.lojaId, id: carga.id, status: carga.status }));
    return { dados: { comentario_id: carga.id, situacao: carga.status }, resumo: carga.resumo };
  },
};

export const apagarComentarioFerramenta: FerramentaDeEscrita<CargaDoComentario> = {
  nome: "apagar_comentario",
  titulo: "Apagar um comentário",
  descricao: "Apaga um comentário (some para todos; se for o principal, a conversa inteira some). Sempre pede confirmação.",
  campos: { comentario_id: { tipo: "id", descricao: "Id do comentário.", obrigatorio: true } },
  tipo: "escrita",
  sobrescreve: true,
  sensivel: true,
  permissoes: ["digital.comments.write"],
  async preparar(ctx, args) {
    await abrirDigital(ctx, "digital.comments.write", "apagar comentários");
    return {
      previa: { apagar_comentario: args.comentario_id },
      resumo: "Prévia de apagar um comentário",
      avisos: ["Se for o comentário principal, as respostas somem junto."],
      carga: { id: String(args.comentario_id), resumo: "Apagou um comentário" },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.comments.write", "apagar comentários");
    await naRota(() => apagarComentario(contexto.admin, { lojaId: contexto.lojaId, id: carga.id }));
    return { dados: { apagado: carga.id }, resumo: carga.resumo };
  },
};

/* ------------------------------------------------------------ entregas */

export const listarEntregas: FerramentaDeLeitura = {
  nome: "listar_entregas",
  titulo: "Ver as entregas dos produtos digitais",
  descricao:
    "Entregas: os pedidos com produto digital (acesso liberado, preparando ou fechado; o e-mail enviado, na fila ou com falha; o que espera: códigos, arquivo final, pré-venda; acesso pausado pelo freio de compartilhamento), as encomendas esperando o arquivo final (com o acesso_id e as respostas do comprador), as pendências e os pedidos esperando pagamento.",
  campos: {},
  tipo: "leitura",
  permissoes: ["digital.deliveries.read"],
  async executar(ctx) {
    const contexto = await abrirDigital(ctx, "digital.deliveries.read", "ver as entregas dos produtos digitais");
    const lido = (await naRota(() => listarEntregasDaLoja(contexto))) as Record<string, unknown> & {
      entregas?: Array<Record<string, unknown>>;
      encomendas: Array<{ acessoId: string; pedidoId: string; numero: number | null; cliente: string; produto: string; unidade: number; unidades: number; entregarAte: string | null; atrasada: boolean; respostas: Array<{ pergunta: string; resposta: string }>; arquivoFinal: { nome: string; enviadoEm: string } | null }>;
    };
    const entregas = (lido.entregas ?? []).slice(0, 150).map((e) => {
      const x = e as {
        pedidoId: string; numero: number | null; numeroNaLoja: number | null; data: string | null; cliente: string; emailDoCliente: string | null; produtos: string[]; acesso: string;
        email: { situacao: string; destino: string | null; enviadoEm: string | null; erro: string | null };
        esperando: { codigos: number; arquivosFinais: number; preVendaEm: string | null }; pausadoPeloFreio: boolean;
      };
      return {
        pedido_id: x.pedidoId,
        pedido: x.numero,
        numero_na_loja: x.numeroNaLoja,
        data: dataEHoraBr(x.data),
        cliente: x.cliente,
        email_do_cliente: x.emailDoCliente,
        produtos: x.produtos,
        acesso: x.acesso,
        email: { situacao: x.email.situacao, para: x.email.destino, enviado_em: dataEHoraBr(x.email.enviadoEm), erro: x.email.erro },
        esperando: { codigos: x.esperando.codigos, arquivos_finais: x.esperando.arquivosFinais, pre_venda: dataEHoraBr(x.esperando.preVendaEm) },
        pausado_pelo_freio: x.pausadoPeloFreio,
      };
    });
    const encomendas = lido.encomendas.map((e) => ({
      acesso_id: e.acessoId,
      pedido_id: e.pedidoId,
      pedido: e.numero,
      cliente: e.cliente,
      produto: e.produto,
      unidade: `${e.unidade} de ${e.unidades}`,
      entregar_ate: e.entregarAte,
      atrasada: e.atrasada,
      respostas_do_comprador: e.respostas,
      arquivo_final: e.arquivoFinal ? { nome: e.arquivoFinal.nome, enviado_em: dataEHoraBr(e.arquivoFinal.enviadoEm) } : null,
    }));
    const { entregas: _e, encomendas: _c, podeEditar: _p, ...resto } = lido;
    return {
      dados: { _observacao: AVISO_DE_DADOS, entregas, encomendas, ...resto },
      resumo: `Consultou as entregas dos produtos digitais (${contagem(entregas.length, "pedido", "pedidos")})`,
    };
  },
};

type CargaDaEntrega = { pedidoId: string; corpo: Record<string, unknown>; descricao: string };

const ACOES: Record<AcaoNaEntrega, string> = {
  reenviar: "reenviar o e-mail de acesso",
  link: "gerar o link da entrega",
  liberar: "liberar a entrega agora (mesmo sem pagamento registrado)",
  anexar: "anexar o arquivo final da encomenda (o comprador recebe)",
  reativar: "reativar o acesso pausado pelo freio (sai um e-mail novo)",
};

export const agirNaEntregaFerramenta: FerramentaDeEscrita<CargaDaEntrega> = {
  nome: "agir_na_entrega",
  titulo: "Agir numa entrega",
  descricao:
    "Os botões da tela Entregas num pedido: reenviar (o e-mail de acesso volta para a fila; pode ir para outro e-mail), link (um link da entrega para a pessoa mandar ao comprador pelo WhatsApp), liberar (entrega agora, mesmo sem o pagamento registrado), anexar (o arquivo final de uma encomenda: acesso_id + arquivo) e reativar (o acesso que o freio de compartilhamento pausou). Tudo que manda e-mail ao comprador pede confirmação.",
  campos: {
    pedido_id: { tipo: "id", descricao: "Id do pedido (de listar_entregas).", obrigatorio: true },
    acao: { tipo: "opcao", descricao: "reenviar, link, liberar, anexar ou reativar.", opcoes: ["reenviar", "link", "liberar", "anexar", "reativar"], obrigatorio: true },
    email: { tipo: "texto", descricao: "Com reenviar: outro e-mail (opcional).", max: 254 },
    acesso_id: { tipo: "id", descricao: "Com anexar: o acesso_id da encomenda." },
    arquivo: { tipo: "texto", descricao: "Com anexar: o arquivo final (id da biblioteca ou \"envio:...\" de pedir_arquivo_digital).", max: 200 },
  },
  tipo: "escrita",
  permissoes: ["digital.deliveries.write"],
  sensivel: (args) => args.acao !== "link",
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.deliveries.write", "mexer nas entregas dos produtos digitais");
    const acao = args.acao as AcaoNaEntrega;
    const corpo: Record<string, unknown> = { acao };
    if (acao === "reenviar" && args.email) corpo.email = args.email;
    if (acao === "anexar") {
      if (!args.acesso_id || !args.arquivo) recusar("Para anexar, diga o acesso_id da encomenda e o arquivo.");
      corpo.acessoId = args.acesso_id;
      corpo.arquivoId = (await arquivoIndicado(ctx, contexto, args.arquivo)).id;
    }
    const { data } = await contexto.admin.from("orders").select("number").eq("id", String(args.pedido_id)).eq("user_id", contexto.lojaId).maybeSingle();
    if (!data) recusar("Pedido não encontrado. Use listar_entregas.");
    const numero = (data as { number: number | null }).number;
    return {
      previa: { pedido: numero, acao: ACOES[acao], ...(corpo.email ? { para: corpo.email } : {}) },
      resumo: `Prévia de ${ACOES[acao]} no pedido ${numero ?? ""}`,
      avisos: acao === "link" ? [] : ["O comprador recebe um e-mail em nome da loja."],
      carga: { pedidoId: String(args.pedido_id), corpo, descricao: `${ACOES[acao]} no pedido ${numero ?? ""}` },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.deliveries.write", "mexer nas entregas dos produtos digitais");
    const feito = (await naRota(() => agirNaEntrega(contexto, carga.pedidoId, carga.corpo, pedidoDoAssistente(ctx)))) as Record<string, unknown>;
    const { ok: _ok, ...resto } = feito;
    return {
      dados: { ...resto, ...(carga.corpo.acao === "link" ? { proximo_passo: "Mostre o link exatamente como veio; a pessoa manda ao comprador." } : {}) },
      resumo: carga.descricao.charAt(0).toUpperCase() + carga.descricao.slice(1),
    };
  },
};

export const FERRAMENTAS_DE_CLIENTES_DIGITAIS: Ferramenta[] = [
  listarAcessos,
  darAcesso,
  mudarAcesso,
  listarComentarios,
  responderComentarioFerramenta,
  mudarComentario,
  apagarComentarioFerramenta,
  listarEntregas,
  agirNaEntregaFerramenta,
] as Ferramenta[];

