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
 */
/**
 * Valida se uma string é um IP válido
 */
function validarIP(ip: string | undefined): string | undefined {
  if (!ip || ip.length < 7) return undefined; // IP mínimo: "1.1.1.1" = 7 chars
  
  // Validar IPv4
  const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
  if (ipv4Regex.test(ip)) {
    const parts = ip.split('.');
    if (parts.length === 4 && parts.every(part => {
      const num = parseInt(part, 10);
      return !isNaN(num) && num >= 0 && num <= 255;
    })) {
      return ip;
    }
  }
  
  // Validar IPv6 básico
  const ipv6Regex = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$|^::[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){0,6}$|^[0-9a-fA-F]{0,4}::[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){0,5}$/;
  if (ipv6Regex.test(ip)) {
    return ip;
  }
  
  // IP inválido - não salvar
  console.warn(`IP inválido detectado e ignorado: "${ip}"`);
  return undefined;
}

export async function registrarLogin(
  ctx: 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;

  // Validar e sanitizar IP antes de salvar
  const ipAddressValidado = validarIP(dados.ipAddress);

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

// Helpers para extrair informações do userAgent
function extrairDevice(userAgent: string): string {
  const ua = userAgent.toLowerCase();
  
  // Detectar dispositivos móveis primeiro
  if (/mobile|android|iphone|ipod|blackberry|opera mini|iemobile|wpdesktop/i.test(ua)) {
    // Verificar se é tablet
    if (/ipad|tablet|playbook|silk|(android(?!.*mobile))/i.test(ua)) {
      return "Tablet";
    }
    return "Mobile";
  }
  
  // Detectar outros dispositivos
  if (/smart-tv|smarttv|googletv|appletv|roku|chromecast/i.test(ua)) {
    return "Smart TV";
  }
  
  if (/watch|wear/i.test(ua)) {
    return "Smart Watch";
  }
  
  // Padrão: Desktop
  return "Desktop";
}

function extrairBrowser(userAgent: string): string {
  const ua = userAgent.toLowerCase();
  
  // Ordem de detecção é importante (Edge deve vir antes de Chrome)
  if (/edgios/i.test(ua)) {
    return "Edge iOS";
  }
  
  if (/edg/i.test(ua)) {
    // Extrair versão do Edge
    const match = ua.match(/edg[e\/]([\d.]+)/i);
    return match ? `Edge ${match[1]}` : "Edge";
  }
  
  if (/opr|opera/i.test(ua)) {
    const match = ua.match(/(?:opr|opera)[\/\s]([\d.]+)/i);
    return match ? `Opera ${match[1]}` : "Opera";
  }
  
  if (/chrome|crios/i.test(ua) && !/edg|opr|opera/i.test(ua)) {
    const match = ua.match(/chrome[/\s]([\d.]+)/i);
    return match ? `Chrome ${match[1]}` : "Chrome";
  }
  
  if (/firefox|fxios/i.test(ua)) {
    const match = ua.match(/firefox[/\s]([\d.]+)/i);
    return match ? `Firefox ${match[1]}` : "Firefox";
  }
  
  if (/safari/i.test(ua) && !/chrome|crios|android/i.test(ua)) {
    const match = ua.match(/version[/\s]([\d.]+)/i);
    return match ? `Safari ${match[1]}` : "Safari";
  }
  
  if (/msie|trident/i.test(ua)) {
    const match = ua.match(/(?:msie |rv:)([\d.]+)/i);
    return match ? `Internet Explorer ${match[1]}` : "Internet Explorer";
  }
  
  if (/samsungbrowser/i.test(ua)) {
    return "Samsung Internet";
  }
  
  if (/ucbrowser/i.test(ua)) {
    return "UC Browser";
  }
  
  if (/micromessenger/i.test(ua)) {
    return "WeChat";
  }
  
  if (/baiduboxapp/i.test(ua)) {
    return "Baidu Browser";
  }
  
  return "Desconhecido";
}

function extrairSistema(userAgent: string): string {
  const ua = userAgent.toLowerCase();
  
  // Windows
  if (/windows nt 10.0/i.test(ua)) {
    return "Windows 10/11";
  }
  if (/windows nt 6.3/i.test(ua)) {
    return "Windows 8.1";
  }
  if (/windows nt 6.2/i.test(ua)) {
    return "Windows 8";
  }
  if (/windows nt 6.1/i.test(ua)) {
    return "Windows 7";
  }
  if (/windows nt 6.0/i.test(ua)) {
    return "Windows Vista";
  }
  if (/windows nt 5.1/i.test(ua)) {
    return "Windows XP";
  }
  if (/windows/i.test(ua)) {
    return "Windows";
  }
  
  // macOS
  if (/macintosh|mac os x/i.test(ua)) {
    const match = ua.match(/mac os x ([\d_]+)/i);
    if (match) {
      const version = match[1].replace(/_/g, '.');
      return `macOS ${version}`;
    }
    return "macOS";
  }
  
  // iOS
  if (/iphone|ipad|ipod/i.test(ua)) {
    const match = ua.match(/os ([\d_]+)/i);
    if (match) {
      const version = match[1].replace(/_/g, '.');
      return `iOS ${version}`;
    }
    return "iOS";
  }
  
  // Android
  if (/android/i.test(ua)) {
    const match = ua.match(/android ([\d.]+)/i);
    if (match) {
      return `Android ${match[1]}`;
    }
    return "Android";
  }
  
  // Linux
  if (/linux/i.test(ua)) {
    // Tentar identificar distribuição
    if (/ubuntu/i.test(ua)) {
      return "Ubuntu";
    }
    if (/debian/i.test(ua)) {
      return "Debian";
    }
    if (/fedora/i.test(ua)) {
      return "Fedora";
    }
    if (/centos/i.test(ua)) {
      return "CentOS";
    }
    if (/redhat/i.test(ua)) {
      return "Red Hat";
    }
    if (/suse/i.test(ua)) {
      return "SUSE";
    }
    return "Linux";
  }
  
  // Chrome OS
  if (/cros/i.test(ua)) {
    return "Chrome OS";
  }
  
  // BlackBerry
  if (/blackberry/i.test(ua)) {
    return "BlackBerry OS";
  }
  
  // Windows Phone
  if (/windows phone/i.test(ua)) {
    return "Windows Phone";
  }
  
  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
    };
  },
});
