import { FraudRule, VtuTransaction, GiftCardTransaction, User } from "../drizzle/schema";
import * as db from "./db";

export interface FraudCheckContext {
  user: User;
  transactionAmount: string;
  transactionType: "vtu" | "giftcard" | "deposit";
  phoneNumber?: string;
  deviceFingerprint?: string;
  ipAddress?: string;
  location?: string;
}

export interface FraudCheckResult {
  isFraudulent: boolean;
  triggeredRules: Array<{
    ruleId: number;
    ruleName: string;
    severity: "low" | "medium" | "high" | "critical";
    action: "alert" | "block" | "review";
    reason: string;
  }>;
  shouldBlock: boolean;
}

/**
 * Velocity Check: Multiple transactions within a time window
 */
async function checkVelocity(
  userId: number,
  timeWindowMinutes: number = 60,
  maxTransactions: number = 5
): Promise<boolean> {
  const transactions = await db.getWalletTransactions(userId, 100, 0);
  const now = Date.now();
  const windowStart = now - timeWindowMinutes * 60 * 1000;

  const recentTransactions = transactions.filter(
    (t) => new Date(t.createdAt).getTime() > windowStart
  );

  return recentTransactions.length > maxTransactions;
}

/**
 * Amount Threshold Check: Transaction exceeds limit
 */
async function checkAmountThreshold(
  amount: string,
  threshold: string
): Promise<boolean> {
  return parseFloat(amount) > parseFloat(threshold);
}

/**
 * Device Fingerprint Check: New device detection
 */
function checkDeviceFingerprint(
  userDeviceFingerprint: string | null,
  currentDeviceFingerprint: string | null
): boolean {
  if (!userDeviceFingerprint || !currentDeviceFingerprint) {
    return false;
  }
  return userDeviceFingerprint !== currentDeviceFingerprint;
}

/**
 * Geo-Anomaly Check: Impossible travel detection
 */
function checkGeoAnomaly(
  userLastLocation: string | null,
  currentLocation: string | null,
  timeSinceLastTransaction: number
): boolean {
  if (!userLastLocation || !currentLocation) {
    return false;
  }

  // Simple check: if location changed within 5 minutes, it's suspicious
  // In production, use actual distance calculation
  const IMPOSSIBLE_TRAVEL_TIME_MINUTES = 5;
  const timeSinceLastMinutes = timeSinceLastTransaction / (1000 * 60);

  if (timeSinceLastMinutes < IMPOSSIBLE_TRAVEL_TIME_MINUTES) {
    return userLastLocation !== currentLocation;
  }

  return false;
}

/**
 * Main fraud detection engine
 */
export async function evaluateFraudRisks(
  context: FraudCheckContext
): Promise<FraudCheckResult> {
  const rules = await db.getFraudRules();
  const triggeredRules: FraudCheckResult["triggeredRules"] = [];
  let shouldBlock = false;

  // Evaluate each rule
  for (const rule of rules) {
    let isTriggered = false;
    let reason = "";

    try {
      if (rule.ruleType === "velocity") {
        // Parse parameters: { timeWindowMinutes, maxTransactions }
        const params = rule.parameters ? JSON.parse(rule.parameters) : { timeWindowMinutes: 60, maxTransactions: 5 };
        isTriggered = await checkVelocity(context.user.id, params.timeWindowMinutes, params.maxTransactions);
        reason = `Multiple transactions (${params.maxTransactions}+) within ${params.timeWindowMinutes} minutes`;
      } else if (rule.ruleType === "amount_threshold") {
        // Parse parameters: { threshold }
        const params = rule.parameters ? JSON.parse(rule.parameters) : { threshold: "100000" };
        isTriggered = await checkAmountThreshold(context.transactionAmount, params.threshold);
        reason = `Transaction amount (₦${context.transactionAmount}) exceeds threshold (₦${params.threshold})`;
      } else if (rule.ruleType === "device_fingerprint") {
        isTriggered = checkDeviceFingerprint(context.user.deviceFingerprint || null, context.deviceFingerprint || null);
        reason = "New device detected";
      } else if (rule.ruleType === "geo_anomaly") {
        const timeSinceLastTx = context.user.lastSignedIn ? Date.now() - new Date(context.user.lastSignedIn).getTime() : 0;
        isTriggered = checkGeoAnomaly(context.user.lastLocation || null, context.location || null, timeSinceLastTx);
        reason = "Impossible travel detected";
      }

      if (isTriggered) {
        triggeredRules.push({
          ruleId: rule.id,
          ruleName: rule.name,
          severity: rule.severity,
          action: rule.action,
          reason,
        });

        // Check if any rule requires blocking
        if (rule.action === "block" && rule.severity === "critical") {
          shouldBlock = true;
        }
      }
    } catch (error) {
      console.error(`[FraudEngine] Error evaluating rule ${rule.id}:`, error);
    }
  }

  return {
    isFraudulent: triggeredRules.length > 0,
    triggeredRules,
    shouldBlock,
  };
}

/**
 * Create fraud alerts for triggered rules
 */
export async function createFraudAlerts(
  userId: number,
  transactionId: number | null,
  fraudCheckResult: FraudCheckResult,
  user: User
): Promise<void> {
  for (const rule of fraudCheckResult.triggeredRules) {
    await db.createFraudAlert({
      userId,
      transactionId,
      ruleId: rule.ruleId,
      ruleName: rule.ruleName,
      severity: rule.severity,
      transactionAmount: "0", // Would be passed from context
      userDetails: JSON.stringify({
        name: user.name || "Unknown",
        email: user.email || "Unknown",
        openId: user.openId,
        kycStatus: user.kycStatus,
      }),
      status: "new",
    });
  }
}

