import { v } from "convex/values";
import { mutation, query, QueryCtx, MutationCtx } from "./_generated/server";
import { Doc, Id } from "./_generated/dataModel";

/**
 * Helper para registrar tentativas de login
 */
export async function registrarLogin(
  ctx: QueryCtx | MutationCtx,
  dados: {
    usuarioId?: Id<"usuarios">;
    matriculaOuEmail: string;
    sucesso: boolean;
    motivoFalha?: string;
    ipAddress?: string;
    userAgent?: string;
  }
) {
  // Extrair informações do userAgent
  const device = dados.userAgent ? extrairDevice(dados.userAgent) : undefined;
  const browser = dados.userAgent ? extrairBrowser(dados.userAgent) : undefined;
  const sistema = dados.userAgent ? extrairSistema(dados.userAgent) : undefined;

  await ctx.db.insert("logsLogin", {
    usuarioId: dados.usuarioId,
    matriculaOuEmail: dados.matriculaOuEmail,
    sucesso: dados.sucesso,
    motivoFalha: dados.motivoFalha,
    ipAddress: dados.ipAddress,
    userAgent: dados.userAgent,
    device,
    browser,
    sistema,
    timestamp: Date.now(),
  });
}

// Helpers para extrair informações do userAgent
function extrairDevice(userAgent: string): string {
  if (/mobile/i.test(userAgent)) return "Mobile";
  if (/tablet/i.test(userAgent)) return "Tablet";
  return "Desktop";
}

function extrairBrowser(userAgent: string): string {
  if (/edg/i.test(userAgent)) return "Edge";
  if (/chrome/i.test(userAgent)) return "Chrome";
  if (/firefox/i.test(userAgent)) return "Firefox";
  if (/safari/i.test(userAgent)) return "Safari";
  if (/opera/i.test(userAgent)) return "Opera";
  return "Desconhecido";
}

function extrairSistema(userAgent: string): string {
  if (/windows/i.test(userAgent)) return "Windows";
  if (/mac/i.test(userAgent)) return "MacOS";
  if (/linux/i.test(userAgent)) return "Linux";
  if (/android/i.test(userAgent)) return "Android";
  if (/ios/i.test(userAgent)) return "iOS";
  return "Desconhecido";
}

/**
 * Lista histórico de logins de um usuário
 */
export const listarLoginsUsuario = query({
  args: {
    usuarioId: v.id("usuarios"),
    limite: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const logs = await ctx.db
      .query("logsLogin")
      .withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId))
      .order("desc")
      .take(args.limite || 50);

    return logs;
  },
});

/**
 * Lista todos os logins do sistema
 */
export const listarTodosLogins = query({
  args: {
    limite: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const logs = await ctx.db
      .query("logsLogin")
      .withIndex("by_timestamp")
      .order("desc")
      .take(args.limite || 50);

    return logs;
  },
});

/**
 * Lista tentativas de login falhadas
 */
export const listarTentativasFalhas = query({
  args: {
    horasAtras: v.optional(v.number()), // padrão 24h
    limite: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const horasAtras = args.horasAtras || 24;
    const dataLimite = Date.now() - horasAtras * 60 * 60 * 1000;

    const logs = await ctx.db
      .query("logsLogin")
      .withIndex("by_sucesso", (q) => q.eq("sucesso", false))
      .filter((q) => q.gte(q.field("timestamp"), dataLimite))
      .order("desc")
      .take(args.limite || 100);

    // Agrupar por IP para detectar possíveis ataques
    const porIP: Record<string, number> = {};
    logs.forEach((log) => {
      if (log.ipAddress) {
        porIP[log.ipAddress] = (porIP[log.ipAddress] || 0) + 1;
      }
    });

    return {
      logs,
      tentativasPorIP: porIP,
      total: logs.length,
    };
  },
});

/**
 * Obtém estatísticas de login
 */
export const obterEstatisticasLogin = query({
  args: {
    dias: v.optional(v.number()), // padrão 30 dias
  },
  handler: async (ctx, args) => {
    const dias = args.dias || 30;
    const dataInicio = Date.now() - dias * 24 * 60 * 60 * 1000;

    const logs = await ctx.db
      .query("logsLogin")
      .withIndex("by_timestamp")
      .filter((q) => q.gte(q.field("timestamp"), dataInicio))
      .collect();

    // Total de logins bem-sucedidos vs falhos
    const sucessos = logs.filter((l) => l.sucesso).length;
    const falhas = logs.filter((l) => !l.sucesso).length;

    // Logins por dia
    const porDia: Record<string, { sucesso: number; falha: number }> = {};
    logs.forEach((log) => {
      const data = new Date(log.timestamp);
      const dia = data.toISOString().split("T")[0];
      if (!porDia[dia]) {
        porDia[dia] = { sucesso: 0, falha: 0 };
      }
      if (log.sucesso) {
        porDia[dia].sucesso++;
      } else {
        porDia[dia].falha++;
      }
    });

    // Logins por horário (hora do dia)
    const porHorario: Record<number, number> = {};
    logs.filter((l) => l.sucesso).forEach((log) => {
      const hora = new Date(log.timestamp).getHours();
      porHorario[hora] = (porHorario[hora] || 0) + 1;
    });

    // Browser mais usado
    const porBrowser: Record<string, number> = {};
    logs.filter((l) => l.sucesso).forEach((log) => {
      if (log.browser) {
        porBrowser[log.browser] = (porBrowser[log.browser] || 0) + 1;
      }
    });

    // Dispositivos mais usados
    const porDevice: Record<string, number> = {};
    logs.filter((l) => l.sucesso).forEach((log) => {
      if (log.device) {
        porDevice[log.device] = (porDevice[log.device] || 0) + 1;
      }
    });

    return {
      total: logs.length,
      sucessos,
      falhas,
      taxaSucesso: logs.length > 0 ? (sucessos / logs.length) * 100 : 0,
      porDia,
      porHorario,
      porBrowser,
      porDevice,
    };
  },
});

/**
 * Verifica se um IP está sendo suspeito (muitas tentativas falhas)
 */
export const verificarIPSuspeito = query({
  args: {
    ipAddress: v.string(),
    minutosAtras: v.optional(v.number()), // padrão 15 minutos
  },
  handler: async (ctx, args) => {
    const minutosAtras = args.minutosAtras || 15;
    const dataLimite = Date.now() - minutosAtras * 60 * 1000;

    const tentativas = await ctx.db
      .query("logsLogin")
      .withIndex("by_ip", (q) => q.eq("ipAddress", args.ipAddress))
      .filter((q) => q.gte(q.field("timestamp"), dataLimite))
      .collect();

    const falhas = tentativas.filter((t) => !t.sucesso).length;

    return {
      tentativasTotal: tentativas.length,
      tentativasFalhas: falhas,
      suspeito: falhas >= 5, // 5 ou mais tentativas falhas em 15 minutos
    };
  },
});

