// src/services/auditLogger.js
// === SECURITY HARDENING: AUDIT LOGS & ANOMALY FLAGS ===
// Enhanced audit logging with risk levels and anomaly detection

const db = require('../db');

// === SECURITY HARDENING: AUDIT LOGS & ANOMALY FLAGS ===
// Risk levels for audit events
const RISK_LEVELS = {
  INFO: 'INFO',
  SUSPICIOUS: 'SUSPICIOUS',
  HIGH_RISK: 'HIGH_RISK',
};

/**
 * Log an authentication event with risk level
 * 
 * @param {Object} params
 * @param {string} params.userId - User ID (can be null for failed attempts)
 * @param {string} params.action - Action type (e.g., 'login', 'token_refresh', 'otp_request', 'otp_verify')
 * @param {string} params.status - Status ('success', 'failed', 'blocked')
 * @param {string} params.riskLevel - Risk level (INFO, SUSPICIOUS, HIGH_RISK)
 * @param {string} params.deviceId - Device identifier
 * @param {string} params.ipAddress - IP address
 * @param {string} params.userAgent - User agent
 * @param {Object} params.meta - Additional metadata
 */
async function logAuthEvent({
  userId = null,
  action,
  status,
  riskLevel = RISK_LEVELS.INFO,
  deviceId = null,
  ipAddress = null,
  userAgent = null,
  meta = {},
}) {
  try {
    // Ensure risk_level column exists (add if not present)
    await ensureRiskLevelColumn();

    await db.query(
      `INSERT INTO auth_audit (
        user_id, action, status, risk_level, device_id, ip_address, user_agent, meta
      )
      VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
      [
        userId,
        action,
        status,
        riskLevel,
        deviceId,
        ipAddress,
        userAgent,
        JSON.stringify(meta),
      ]
    );
  } catch (err) {
    console.error('Failed to log auth event:', err);
    // Don't throw - audit logging should not break the main flow
  }
}

/**
 * Ensure risk_level column exists in auth_audit table
 */
async function ensureRiskLevelColumn() {
  try {
    await db.query(`
      DO $$
      BEGIN
        IF NOT EXISTS (
          SELECT 1 FROM information_schema.columns
          WHERE table_name = 'auth_audit' AND column_name = 'risk_level'
        ) THEN
          ALTER TABLE auth_audit ADD COLUMN risk_level VARCHAR(20) DEFAULT 'INFO';
          CREATE INDEX IF NOT EXISTS idx_auth_audit_risk_level ON auth_audit(risk_level);
        END IF;
      END $$;
    `);
  } catch (err) {
    // Column might already exist or table might not exist yet
    // This is fine, the insert will handle it
  }
}

/**
 * Log suspicious OTP verification attempts
 */
async function logSuspiciousOtpAttempt(phone, ipAddress, userAgent, reason) {
  await logAuthEvent({
    userId: null, // Phone not yet linked to user
    action: 'otp_verify',
    status: 'failed',
    riskLevel: RISK_LEVELS.SUSPICIOUS,
    ipAddress,
    userAgent,
    meta: {
      phone: phone.replace(/\d(?=\d{4})/g, '*'), // Mask phone
      reason,
      message: 'Multiple failed OTP attempts detected',
    },
  });
}

/**
 * Log blocked login from disallowed IP
 */
async function logBlockedIpLogin(ipAddress, userAgent, userId = null) {
  await logAuthEvent({
    userId,
    action: 'login',
    status: 'blocked',
    riskLevel: RISK_LEVELS.HIGH_RISK,
    ipAddress,
    userAgent,
    meta: {
      reason: 'blocked_ip_range',
      message: 'Login attempt from blocked IP range',
    },
  });
}

/**
 * Log suspicious refresh event
 */
async function logSuspiciousRefresh(userId, deviceId, ipAddress, userAgent, riskScore, reasons) {
  await logAuthEvent({
    userId,
    action: 'token_refresh',
    status: 'success', // Token was issued, but suspicious
    riskLevel: riskScore >= 50 ? RISK_LEVELS.HIGH_RISK : RISK_LEVELS.SUSPICIOUS,
    deviceId,
    ipAddress,
    userAgent,
    meta: {
      risk_score: riskScore,
      risk_reasons: reasons,
      message: 'Token refresh from suspicious environment',
    },
  });
}

/**
 * Log step-up authentication requirement
 */
async function logStepUpAuthRequired(userId, action, ipAddress, userAgent) {
  await logAuthEvent({
    userId,
    action: `step_up_${action}`,
    status: 'failed',
    riskLevel: RISK_LEVELS.SUSPICIOUS,
    ipAddress,
    userAgent,
    meta: {
      reason: 'step_up_required',
      message: 'Sensitive action requires step-up authentication',
    },
  });
}

/**
 * Helper to check for anomaly patterns (for future alerting)
 * This can be extended to query recent events and detect patterns
 */
async function checkAnomalies(userId, action, ipAddress) {
  try {
    // Example: Check for multiple failed attempts in short time
    if (action === 'otp_verify') {
      const result = await db.query(
        `SELECT COUNT(*) as count
         FROM auth_audit
         WHERE user_id = $1
           AND action = 'otp_verify'
           AND status = 'failed'
           AND risk_level IN ('SUSPICIOUS', 'HIGH_RISK')
           AND created_at > NOW() - INTERVAL '1 hour'`,
        [userId]
      );

      const failedCount = parseInt(result.rows[0]?.count || 0, 10);
      if (failedCount >= 5) {
        // TODO: Trigger alert (email, webhook, etc.)
        console.warn(`[ANOMALY] User ${userId} has ${failedCount} failed OTP attempts in last hour`);
      }
    }
  } catch (err) {
    console.error('Error checking anomalies:', err);
  }
}

/**
 * TODO: Integrate with external alerting systems
 * Example implementations:
 * 
 * async function sendAlert(level, message, metadata) {
 *   // Send to PagerDuty, Slack, email, etc.
 *   if (level === 'HIGH_RISK') {
 *     await sendToPagerDuty(message, metadata);
 *   }
 * }
 */

module.exports = {
  logAuthEvent,
  logSuspiciousOtpAttempt,
  logBlockedIpLogin,
  logSuspiciousRefresh,
  logStepUpAuthRequired,
  checkAnomalies,
  RISK_LEVELS,
};

