import { v } from "convex/values";
import { mutation, query } from "./_generated/server";

/**
 * Listar logs de acesso com filtros
 */
export const listar = query({
  args: {
    usuarioId: v.optional(v.id("usuarios")),
    tipo: v.optional(
      v.union(
        v.literal("login"),
        v.literal("logout"),
        v.literal("acesso_negado"),
        v.literal("senha_alterada"),
        v.literal("sessao_expirada")
      )
    ),
    dataInicio: v.optional(v.number()),
    dataFim: v.optional(v.number()),
    limite: v.optional(v.number()),
  },
  returns: v.array(
    v.object({
      _id: v.id("logsAcesso"),
      tipo: v.union(
        v.literal("login"),
        v.literal("logout"),
        v.literal("acesso_negado"),
        v.literal("senha_alterada"),
        v.literal("sessao_expirada")
      ),
      ipAddress: v.optional(v.string()),
      userAgent: v.optional(v.string()),
      detalhes: v.optional(v.string()),
      timestamp: v.number(),
      usuario: v.optional(
        v.object({
          _id: v.id("usuarios"),
          matricula: v.string(),
          nome: v.string(),
        })
      ),
    })
  ),
  handler: async (ctx, args) => {
    let logs;

    // Filtrar por usuário
    if (args.usuarioId !== undefined) {
      const usuarioId = args.usuarioId; // TypeScript agora sabe que não é undefined
      logs = await ctx.db
        .query("logsAcesso")
        .withIndex("by_usuario", (q) => q.eq("usuarioId", usuarioId))
        .collect();
    } else {
      logs = await ctx.db
        .query("logsAcesso")
        .withIndex("by_timestamp")
        .collect();
    }

    // Filtrar por tipo
    if (args.tipo) {
      logs = logs.filter((log) => log.tipo === args.tipo);
    }

    // Filtrar por data
    if (args.dataInicio) {
      logs = logs.filter((log) => log.timestamp >= args.dataInicio!);
    }
    if (args.dataFim) {
      logs = logs.filter((log) => log.timestamp <= args.dataFim!);
    }

    // Ordenar por timestamp decrescente
    logs.sort((a, b) => b.timestamp - a.timestamp);

    // Limitar resultados
    if (args.limite) {
      logs = logs.slice(0, args.limite);
    }

    // Buscar informações dos usuários
    const resultado = [];
    for (const log of logs) {
      let usuario = undefined;
      if (log.usuarioId) {
        const user = await ctx.db.get(log.usuarioId);
        if (user) {
          usuario = {
            _id: user._id,
            matricula: user.matricula,
            nome: user.nome,
          };
        }
      }

      resultado.push({
        _id: log._id,
        tipo: log.tipo,
        ipAddress: log.ipAddress,
        userAgent: log.userAgent,
        detalhes: log.detalhes,
        timestamp: log.timestamp,
        usuario,
      });
    }

    return resultado;
  },
});

/**
 * Obter estatísticas de acessos
 */
export const estatisticas = query({
  args: {
    dataInicio: v.optional(v.number()),
    dataFim: v.optional(v.number()),
  },
  returns: v.object({
    totalLogins: v.number(),
    totalLogouts: v.number(),
    totalAcessosNegados: v.number(),
    totalSenhasAlteradas: v.number(),
    totalSessoesExpiradas: v.number(),
    loginsPorDia: v.array(
      v.object({
        data: v.string(),
        quantidade: v.number(),
      })
    ),
  }),
  handler: async (ctx, args) => {
    let logs = await ctx.db.query("logsAcesso").collect();

    // Filtrar por data
    if (args.dataInicio) {
      logs = logs.filter((log) => log.timestamp >= args.dataInicio!);
    }
    if (args.dataFim) {
      logs = logs.filter((log) => log.timestamp <= args.dataFim!);
    }

    // Contar por tipo
    const totalLogins = logs.filter((log) => log.tipo === "login").length;
    const totalLogouts = logs.filter((log) => log.tipo === "logout").length;
    const totalAcessosNegados = logs.filter(
      (log) => log.tipo === "acesso_negado"
    ).length;
    const totalSenhasAlteradas = logs.filter(
      (log) => log.tipo === "senha_alterada"
    ).length;
    const totalSessoesExpiradas = logs.filter(
      (log) => log.tipo === "sessao_expirada"
    ).length;

    // Agrupar logins por dia
    const loginsPorDiaMap = new Map<string, number>();
    const loginsOnly = logs.filter((log) => log.tipo === "login");

    for (const log of loginsOnly) {
      const data = new Date(log.timestamp).toISOString().split("T")[0];
      loginsPorDiaMap.set(data, (loginsPorDiaMap.get(data) || 0) + 1);
    }

    const loginsPorDia = Array.from(loginsPorDiaMap.entries())
      .map(([data, quantidade]) => ({ data, quantidade }))
      .sort((a, b) => a.data.localeCompare(b.data));

    return {
      totalLogins,
      totalLogouts,
      totalAcessosNegados,
      totalSenhasAlteradas,
      totalSessoesExpiradas,
      loginsPorDia,
    };
  },
});

/**
 * Limpar logs antigos (apenas TI)
 */
export const limpar = mutation({
  args: {
    dataLimite: v.number(), // Excluir logs anteriores a esta data
  },
  returns: v.object({
    excluidos: v.number(),
  }),
  handler: async (ctx, args) => {
    const logs = await ctx.db
      .query("logsAcesso")
      .withIndex("by_timestamp")
      .collect();

    const logsAntigos = logs.filter((log) => log.timestamp < args.dataLimite);

    for (const log of logsAntigos) {
      await ctx.db.delete(log._id);
    }

    return { excluidos: logsAntigos.length };
  },
});

/**
 * Limpar todos os logs (apenas TI)
 */
export const limparTodos = mutation({
  args: {},
  returns: v.object({
    excluidos: v.number(),
  }),
  handler: async (ctx) => {
    const logs = await ctx.db.query("logsAcesso").collect();

    for (const log of logs) {
      await ctx.db.delete(log._id);
    }

    return { excluidos: logs.length };
  },
});

