/**
 * ═══════════════════════════════════════════════════════════════════════════════
 * LOOPUMAN RATE LIMITING & ANTI-ABUSE SYSTEM
 * ═══════════════════════════════════════════════════════════════════════════════
 * 
 * Protects Loopuman from:
 * - API abuse
 * - Bot attacks
 * - Spam submissions
 * - Account farming
 * - Resource exhaustion
 * 
 * LIMITS:
 * - Messages: 30/minute per user
 * - Task submissions: 60/hour per user
 * - Account creation: 5/hour per IP
 * - Withdrawals: 3/day per user
 * - API calls: 100/minute per user
 * 
 * ═══════════════════════════════════════════════════════════════════════════════
 */

'use strict';

const { createClient } = require('@supabase/supabase-js');

const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_KEY);

// In-memory rate limit storage (use Redis in production for multi-server)
const rateLimitStore = new Map();

// ═══════════════════════════════════════════════════════════════════════════════
// CONFIGURATION
// ═══════════════════════════════════════════════════════════════════════════════

const LIMITS = {
  // User-based limits
  user: {
    messages: { max: 30, windowMs: 60 * 1000 },        // 30/minute
    task_submissions: { max: 60, windowMs: 60 * 60 * 1000 }, // 60/hour
    task_posts: { max: 20, windowMs: 60 * 60 * 1000 }, // 20/hour
    withdrawals: { max: 3, windowMs: 24 * 60 * 60 * 1000 }, // 3/day
    api_calls: { max: 100, windowMs: 60 * 1000 },     // 100/minute
    payment_attempts: { max: 10, windowMs: 60 * 60 * 1000 }, // 10/hour
    disputes: { max: 5, windowMs: 24 * 60 * 60 * 1000 }, // 5/day
    support_messages: { max: 10, windowMs: 60 * 60 * 1000 } // 10/hour
  },
  
  // IP-based limits
  ip: {
    account_creation: { max: 5, windowMs: 60 * 60 * 1000 }, // 5/hour
    login_attempts: { max: 10, windowMs: 15 * 60 * 1000 }, // 10/15min
    api_calls: { max: 200, windowMs: 60 * 1000 }      // 200/minute
  },
  
  // Global limits
  global: {
    new_accounts: { max: 100, windowMs: 60 * 60 * 1000 }, // 100/hour total
    webhooks: { max: 1000, windowMs: 60 * 1000 }      // 1000/minute
  }
};

// ═══════════════════════════════════════════════════════════════════════════════
// CORE RATE LIMITER
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Check if action is within rate limit
 * @param {string} key - Unique identifier (user_id, ip, etc.)
 * @param {string} action - Action type (messages, withdrawals, etc.)
 * @param {Object} limits - Limit configuration
 * @returns {Object} { allowed, remaining, resetIn }
 */
function checkRateLimit(key, action, limits) {
  const now = Date.now();
  const storeKey = `${key}:${action}`;
  
  // Get or create rate limit record
  let record = rateLimitStore.get(storeKey);
  
  if (!record || now > record.resetAt) {
    record = {
      count: 0,
      resetAt: now + limits.windowMs
    };
  }
  
  // Check if within limit
  if (record.count >= limits.max) {
    return {
      allowed: false,
      remaining: 0,
      resetIn: Math.ceil((record.resetAt - now) / 1000),
      message: `Rate limit exceeded. Try again in ${Math.ceil((record.resetAt - now) / 1000)} seconds.`
    };
  }
  
  // Increment counter
  record.count++;
  rateLimitStore.set(storeKey, record);
  
  return {
    allowed: true,
    remaining: limits.max - record.count,
    resetIn: Math.ceil((record.resetAt - now) / 1000)
  };
}

/**
 * User rate limit check
 */
function checkUserLimit(userId, action) {
  const limits = LIMITS.user[action];
  if (!limits) {
    console.warn(`Unknown user rate limit action: ${action}`);
    return { allowed: true };
  }
  return checkRateLimit(`user:${userId}`, action, limits);
}

/**
 * IP rate limit check
 */
function checkIpLimit(ip, action) {
  const limits = LIMITS.ip[action];
  if (!limits) {
    console.warn(`Unknown IP rate limit action: ${action}`);
    return { allowed: true };
  }
  return checkRateLimit(`ip:${ip}`, action, limits);
}

/**
 * Global rate limit check
 */
function checkGlobalLimit(action) {
  const limits = LIMITS.global[action];
  if (!limits) return { allowed: true };
  return checkRateLimit(`global`, action, limits);
}

// ═══════════════════════════════════════════════════════════════════════════════
// MIDDLEWARE FOR EXPRESS
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Express middleware for API rate limiting
 */
function rateLimitMiddleware(action = 'api_calls') {
  return (req, res, next) => {
    const userId = req.user?.id || req.headers['x-user-id'];
    const ip = req.ip || req.headers['x-forwarded-for']?.split(',')[0];
    
    // Check user limit if authenticated
    if (userId) {
      const userCheck = checkUserLimit(userId, action);
      if (!userCheck.allowed) {
        return res.status(429).json({
          error: 'Rate limit exceeded',
          message: userCheck.message,
          retryAfter: userCheck.resetIn
        });
      }
    }
    
    // Check IP limit
    if (ip) {
      const ipCheck = checkIpLimit(ip, action);
      if (!ipCheck.allowed) {
        return res.status(429).json({
          error: 'Rate limit exceeded',
          message: ipCheck.message,
          retryAfter: ipCheck.resetIn
        });
      }
    }
    
    next();
  };
}

// ═══════════════════════════════════════════════════════════════════════════════
// TELEGRAM BOT RATE LIMITER
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Rate limit wrapper for Telegram bot handlers
 */
function botRateLimiter(action = 'messages') {
  return async (ctx, next) => {
    const userId = ctx.from?.id?.toString();
    
    if (!userId) {
      return next();
    }
    
    const check = checkUserLimit(userId, action);
    
    if (!check.allowed) {
      await ctx.reply(
        `⚠️ *Slow down!*\n\n` +
        `You're sending too many requests.\n` +
        `Please wait ${check.resetIn} seconds.\n\n` +
        `_This protects our platform from abuse._`,
        { parse_mode: 'Markdown' }
      );
      return;
    }
    
    return next();
  };
}

// ═══════════════════════════════════════════════════════════════════════════════
// ANTI-ABUSE PATTERNS
// ═══════════════════════════════════════════════════════════════════════════════

const ABUSE_PATTERNS = {
  // Suspicious message patterns
  spam_keywords: [
    'free money', 'guaranteed profit', 'click here',
    'crypto airdrop', 'double your', 'investment opportunity'
  ],
  
  // Suspicious behavior thresholds
  thresholds: {
    rapid_submissions: 10,      // >10 submissions in 5 min
    failed_withdrawals: 5,      // >5 failed withdrawals
    rejected_tasks: 10,         // >10 rejected tasks
    dispute_ratio: 0.3          // >30% tasks disputed
  }
};

/**
 * Check for abuse patterns in user behavior
 */
async function checkForAbuse(userId) {
  const warnings = [];
  
  // Get recent activity
  const fiveMinAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();
  const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
  
  // Check rapid submissions
  const { count: rapidSubmissions } = await supabase
    .from('submissions')
    .select('id', { count: 'exact' })
    .eq('worker_id', userId)
    .gte('created_at', fiveMinAgo);
  
  if (rapidSubmissions > ABUSE_PATTERNS.thresholds.rapid_submissions) {
    warnings.push({
      type: 'rapid_submissions',
      severity: 'high',
      message: `${rapidSubmissions} submissions in 5 minutes`
    });
  }
  
  // Check failed withdrawals
  const { count: failedWithdrawals } = await supabase
    .from('withdrawals')
    .select('id', { count: 'exact' })
    .eq('user_id', userId)
    .eq('status', 'failed')
    .gte('created_at', dayAgo);
  
  if (failedWithdrawals > ABUSE_PATTERNS.thresholds.failed_withdrawals) {
    warnings.push({
      type: 'failed_withdrawals',
      severity: 'medium',
      message: `${failedWithdrawals} failed withdrawals today`
    });
  }
  
  // Calculate dispute ratio
  const { data: taskStats } = await supabase
    .from('submissions')
    .select('status')
    .eq('worker_id', userId);
  
  if (taskStats && taskStats.length >= 10) {
    const disputed = taskStats.filter(t => t.status === 'disputed').length;
    const ratio = disputed / taskStats.length;
    
    if (ratio > ABUSE_PATTERNS.thresholds.dispute_ratio) {
      warnings.push({
        type: 'high_dispute_ratio',
        severity: 'high',
        message: `${(ratio * 100).toFixed(1)}% dispute rate`
      });
    }
  }
  
  // Auto-flag if high severity warnings
  const highSeverity = warnings.filter(w => w.severity === 'high');
  
  if (highSeverity.length >= 2) {
    await supabase
      .from('app_users')
      .update({
        flagged: true,
        flag_reason: 'Automated abuse detection',
        flag_signals: warnings
      })
      .eq('id', userId);
    
    console.log(`🚨 User ${userId} auto-flagged for abuse:`, warnings);
  }
  
  return { warnings, flagged: highSeverity.length >= 2 };
}

// ═══════════════════════════════════════════════════════════════════════════════
// CLEANUP (Run periodically)
// ═══════════════════════════════════════════════════════════════════════════════

/**
 * Clean up expired rate limit records
 * Run every 5 minutes via scheduler
 */
function cleanupExpiredRecords() {
  const now = Date.now();
  let cleaned = 0;
  
  for (const [key, record] of rateLimitStore.entries()) {
    if (now > record.resetAt) {
      rateLimitStore.delete(key);
      cleaned++;
    }
  }
  
  if (cleaned > 0) {
    console.log(`🧹 Cleaned ${cleaned} expired rate limit records`);
  }
}

// Run cleanup every 5 minutes
setInterval(cleanupExpiredRecords, 5 * 60 * 1000);

// ═══════════════════════════════════════════════════════════════════════════════
// EXPORTS
// ═══════════════════════════════════════════════════════════════════════════════

module.exports = {
  // Core functions
  checkRateLimit,
  checkUserLimit,
  checkIpLimit,
  checkGlobalLimit,
  
  // Middleware
  rateLimitMiddleware,
  botRateLimiter,
  
  // Abuse detection
  checkForAbuse,
  ABUSE_PATTERNS,
  
  // Utilities
  cleanupExpiredRecords,
  
  // Config
  LIMITS
};
