/**
 * Anomaly Detection Engine
 * Detects unusual patterns that require human review
 */

import prisma from '@/lib/db';
import { AnomalyResult, AnomalyType, DEFAULT_THRESHOLDS } from './types';

interface OrderData {
  id: string;
  orderNumber: string;
  customerEmail: string;
  customerName: string;
  total: number;
  subtotal: number;
  tax: number;
  shipping: number;
  shippingAddress: Record<string, unknown>;
  items: Array<{
    quantity: number;
    unitPrice: number;
    totalPrice: number;
  }>;
}

export async function detectOrderAnomalies(order: OrderData): Promise<AnomalyResult[]> {
  const anomalies: AnomalyResult[] = [];

  // 1. High value order check
  if (order.total > DEFAULT_THRESHOLDS.highValueOrderAmount) {
    anomalies.push({
      detected: true,
      type: 'high_value_order',
      severity: order.total > DEFAULT_THRESHOLDS.highValueOrderAmount * 2 ? 'high' : 'normal',
      details: {
        orderTotal: order.total,
        threshold: DEFAULT_THRESHOLDS.highValueOrderAmount,
      },
      confidence: 1.0,
    });
  }

  // 2. Unusual quantity check
  for (const item of order.items) {
    if (item.quantity > DEFAULT_THRESHOLDS.unusualQuantityThreshold) {
      anomalies.push({
        detected: true,
        type: 'unusual_quantity',
        severity: 'normal',
        details: {
          quantity: item.quantity,
          threshold: DEFAULT_THRESHOLDS.unusualQuantityThreshold,
        },
        confidence: 0.9,
      });
      break; // Only flag once
    }
  }

  // 3. Rapid orders check (same email within time window)
  const windowStart = new Date();
  windowStart.setMinutes(windowStart.getMinutes() - DEFAULT_THRESHOLDS.rapidOrderWindowMinutes);

  const recentOrders = await prisma.swagOrder.count({
    where: {
      customerEmail: order.customerEmail,
      createdAt: { gte: windowStart },
      id: { not: order.id },
    },
  });

  if (recentOrders >= DEFAULT_THRESHOLDS.rapidOrderCount - 1) {
    anomalies.push({
      detected: true,
      type: 'rapid_orders',
      severity: 'high',
      details: {
        recentOrderCount: recentOrders + 1,
        windowMinutes: DEFAULT_THRESHOLDS.rapidOrderWindowMinutes,
        threshold: DEFAULT_THRESHOLDS.rapidOrderCount,
      },
      confidence: 0.95,
    });
  }

  // 4. Suspicious email patterns
  const suspiciousPatterns = [
    /\+.*@/,  // Plus addressing (test+1@example.com)
    /temp|fake|test|disposable/i,
    /\d{5,}@/,  // Many numbers before @
  ];

  for (const pattern of suspiciousPatterns) {
    if (pattern.test(order.customerEmail)) {
      anomalies.push({
        detected: true,
        type: 'suspicious_email',
        severity: 'low',
        details: {
          email: order.customerEmail,
          pattern: pattern.toString(),
        },
        confidence: 0.7,
      });
      break;
    }
  }

  // 5. Tax calculation verification
  const expectedTaxRate = await getExpectedTaxRate(order.shippingAddress);
  if (expectedTaxRate) {
    const expectedTax = order.subtotal * expectedTaxRate;
    const taxDifference = Math.abs(order.tax - expectedTax) / order.subtotal;
    
    if (taxDifference > DEFAULT_THRESHOLDS.taxMismatchTolerance) {
      anomalies.push({
        detected: true,
        type: 'tax_mismatch',
        severity: 'normal',
        details: {
          actualTax: order.tax,
          expectedTax,
          expectedRate: expectedTaxRate,
          difference: taxDifference,
        },
        confidence: 0.85,
      });
    }
  }

  // 6. Duplicate order check
  const duplicateWindow = new Date();
  duplicateWindow.setHours(duplicateWindow.getHours() - 24);

  const potentialDuplicates = await prisma.swagOrder.findMany({
    where: {
      customerEmail: order.customerEmail,
      total: order.total,
      createdAt: { gte: duplicateWindow },
      id: { not: order.id },
    },
    take: 1,
  });

  if (potentialDuplicates.length > 0) {
    anomalies.push({
      detected: true,
      type: 'duplicate_order',
      severity: 'high',
      details: {
        existingOrderId: potentialDuplicates[0].id,
        existingOrderNumber: potentialDuplicates[0].orderNumber,
        sameTotal: order.total,
      },
      confidence: 0.8,
    });
  }

  return anomalies;
}

async function getExpectedTaxRate(address: Record<string, unknown>): Promise<number | null> {
  // First check for learned patterns
  const state = (address.state as string) || '';
  if (!state) return null;

  const pattern = await prisma.detectedPattern.findUnique({
    where: {
      patternType_patternKey: {
        patternType: 'tax_rate',
        patternKey: `state:${state.toUpperCase()}`,
      },
    },
  });

  if (pattern && pattern.confidence >= DEFAULT_THRESHOLDS.patternConfidenceThreshold) {
    const value = pattern.detectedValue as { rate: number };
    return value.rate;
  }

  // Fallback to default rates
  const defaultRates: Record<string, number> = {
    CA: 0.0725,
    NY: 0.08,
    TX: 0.0625,
    FL: 0.06,
    WA: 0.065,
    // Default for other states
  };

  return defaultRates[state.toUpperCase()] || 0.08;
}

export function getMostSevereAnomaly(anomalies: AnomalyResult[]): AnomalyResult | null {
  if (anomalies.length === 0) return null;

  const severityOrder: Record<string, number> = {
    critical: 4,
    high: 3,
    normal: 2,
    low: 1,
  };

  return anomalies.reduce((most, current) => {
    return severityOrder[current.severity] > severityOrder[most.severity] ? current : most;
  });
}

export function shouldRequireHumanReview(anomalies: AnomalyResult[]): boolean {
  if (anomalies.length === 0) return false;
  
  // Require review for high or critical anomalies
  return anomalies.some(a => a.severity === 'high' || a.severity === 'critical');
}
