import { registerReportAuditLog } from "@/lib/reports/audit";
import type { ReportFilterValue, ReportRequest, ReportTabKey } from "@/lib/reports/contracts";
import { montarArquivoDoRelatorio } from "@/lib/reports/exportar";
import { createReportRuntimeFor, runReport } from "@/lib/reports/service";

import { COMO_ENTREGAR_O_ARQUIVO, entregarArquivo } from "../arquivos";
import { AVISO_DE_DADOS, diasEntre, exigir, hojeEmBrasilia, periodoBr, recusar } from "./comum";
import type { FerramentaDeLeitura } from "./tipos";

/*
 * Os relatórios do painel (Relatórios), pelo mesmo serviço da tela
 * (lib/reports/service.ts). O serviço lê com a chave de serviço, sempre
 * filtrado pelas empresas do contexto da pessoa — o mesmo contexto que a rota
 * /api/reports monta a partir da sessão. Aqui o contexto vem da chave do
 * assistente, que já conferiu pessoa, empresa e vínculo.
 */

const ABA: Record<string, ReportTabKey> = { vendas: "sales", produtos: "products", clientes: "customers", financeiro: "financial" };

function valorLegivel(valor: unknown, tipo: string) {
  if (valor === null || valor === undefined || valor === "") return null;
  if (tipo === "currency" || tipo === "number" || tipo === "percent") {
    const numero = Number(valor);
    return Number.isFinite(numero) ? Math.round(numero * 100) / 100 : valor;
  }
  return valor;
}

export const gerarRelatorio: FerramentaDeLeitura = {
  nome: "gerar_relatorio",
  titulo: "Gerar um relatório",
  descricao:
    "Gera um dos relatórios do painel (vendas, produtos, clientes ou financeiro) num período, com os indicadores (faturamento, ticket médio, lucro, recebido...) e as primeiras linhas da tabela. Com `arquivo`, também devolve um link para baixar o relatório inteiro em Excel ou CSV (vale 24 horas). Sem datas, usa do dia 1º do mês até hoje.",
  campos: {
    aba: { tipo: "opcao", descricao: "Qual relatório: vendas, produtos, clientes ou financeiro.", opcoes: ["vendas", "produtos", "clientes", "financeiro"], obrigatorio: true },
    inicio: { tipo: "data", descricao: "Primeiro dia do período. O padrão é o dia 1º do mês." },
    fim: { tipo: "data", descricao: "Último dia do período. O padrão é hoje." },
    cliente_id: { tipo: "id", descricao: "Só deste cliente (de buscar_clientes)." },
    categoria_id: { tipo: "id", descricao: "Só desta categoria de produto (de listar_categorias)." },
    cidade: { tipo: "texto", descricao: "Só clientes desta cidade (vendas e clientes).", max: 80 },
    estado: { tipo: "texto", descricao: "Só clientes deste estado, sigla (vendas e clientes).", min: 2, max: 2 },
    busca: { tipo: "texto", descricao: "Texto para filtrar as linhas (nome, número...).", max: 80 },
    ordenar_por: { tipo: "texto", descricao: "Id de uma coluna (as colunas vêm na resposta). Sem isto, a ordem da tela.", max: 60 },
    ordem: { tipo: "opcao", descricao: "crescente ou decrescente (padrão).", opcoes: ["crescente", "decrescente"] },
    linhas: { tipo: "inteiro", descricao: "Quantas linhas da tabela devolver aqui. O padrão é 10.", min: 1, max: 50 },
    arquivo: { tipo: "opcao", descricao: "Também gerar o arquivo completo: xlsx (Excel) ou csv.", opcoes: ["xlsx", "csv"] },
  },
  tipo: "leitura",
  permissoes: ["reports.read"],
  async executar(ctx, args) {
    exigir(ctx, "reports.read", "ver os relatórios");
    const hoje = hojeEmBrasilia();
    const inicio = (args.inicio as string | undefined) ?? `${hoje.slice(0, 8)}01`;
    const fim = (args.fim as string | undefined) ?? hoje;
    if (fim < inicio) recusar("O fim do período é antes do início.");
    if (diasEntre(inicio, fim) > 731) recusar("Período grande demais. Peça no máximo 2 anos de cada vez.");

    const filtros: Record<string, ReportFilterValue> = { startDate: inicio, endDate: fim };
    if (args.cliente_id) filtros.client = [String(args.cliente_id)];
    if (args.categoria_id) filtros.category = [String(args.categoria_id)];
    if (args.cidade) filtros.city = [String(args.cidade)];
    if (args.estado) filtros.state = [String(args.estado).toUpperCase()];

    const quantas = (args.linhas as number | undefined) ?? 10;
    const pedido: ReportRequest = {
      tab: ABA[String(args.aba)],
      filters: filtros,
      page: 1,
      pageSize: args.arquivo ? 5000 : quantas,
      search: String(args.busca ?? ""),
      sort: args.ordenar_por ? { columnId: String(args.ordenar_por), direction: args.ordem === "crescente" ? "asc" : "desc" } : null,
      custom: null,
      exportAllRows: Boolean(args.arquivo),
      skipAudit: true,
    };

    const runtime = await createReportRuntimeFor({ ctx: ctx.empresa, user: ctx.user, admin: ctx.admin });
    let relatorio;
    try {
      relatorio = await runReport(runtime, pedido);
    } catch (erro) {
      console.error("[mcp] relatório", erro instanceof Error ? erro.message : erro);
      recusar("Não foi possível gerar o relatório agora. Tente de novo em instantes ou com um período menor.");
    }
    if (pedido.sort && !relatorio.columns.some((coluna) => coluna.id === pedido.sort?.columnId)) {
      recusar(`Coluna "${pedido.sort.columnId}" não existe neste relatório. Colunas: ${relatorio.columns.map((c) => c.id).join(", ")}.`);
    }

    const quemGerou = String(ctx.user.user_metadata?.name || ctx.user.user_metadata?.full_name || ctx.user.email || ctx.user.id);
    const registro = (eventType: "generate" | "export", format: "screen" | "csv" | "xlsx") =>
      registerReportAuditLog({
        admin: ctx.admin,
        companyId: ctx.empresa.companyId,
        userId: ctx.user.id,
        generatedBy: `${quemGerou} (assistente)`,
        timezone: "America/Sao_Paulo",
        eventType,
        format,
        report: relatorio,
        request: pedido,
        metadata: { origem: "assistente" },
      }).catch((erro: unknown) => console.error("[mcp] registro do relatório", erro instanceof Error ? erro.message : erro));
    await registro("generate", "screen");

    const indicadores = relatorio.kpis.map((kpi) => ({ indicador: kpi.label, valor: valorLegivel(kpi.value, kpi.type), tipo: kpi.type === "currency" ? "reais" : kpi.type === "percent" ? "porcentagem" : "número" }));
    const colunas = relatorio.columns.map((coluna) => ({ id: coluna.id, nome: coluna.label }));
    const primeiras = relatorio.rows.slice(0, quantas).map((linha) =>
      Object.fromEntries(relatorio.columns.map((coluna) => [coluna.label, valorLegivel(linha[coluna.id], coluna.type)]))
    );

    let arquivo = null;
    if (args.arquivo) {
      const formato = args.arquivo === "csv" ? "csv" : "xlsx";
      const pronto = montarArquivoDoRelatorio({ report: relatorio, request: pedido, format: formato, generatedBy: `${quemGerou} (assistente)`, timezone: "America/Sao_Paulo" });
      arquivo = await entregarArquivo(ctx, { conteudo: pronto.conteudo, nome: pronto.nome, tipo: pronto.tipo });
      await registro("export", formato);
    }

    return {
      dados: {
        _observacao: AVISO_DE_DADOS,
        relatorio: relatorio.title,
        periodo: { inicio, fim },
        indicadores,
        total_de_linhas: relatorio.totalRows,
        colunas,
        primeiras_linhas: primeiras,
        ...(arquivo ? { arquivo: { ...arquivo, como_entregar: COMO_ENTREGAR_O_ARQUIVO } } : {}),
      },
      resumo: `Gerou o relatório de ${args.aba} ${periodoBr(inicio, fim)}${arquivo ? ` (${String(args.arquivo).toUpperCase()})` : ""}`,
    };
  },
};
