import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';

export interface FraudCheckResult {
  score: number;
  factors: { name: string; score: number; detail?: string }[];
  action: 'allow' | 'captcha' | 'spam';
}

const DISPOSABLE_DOMAINS = new Set([
  'mailinator.com',
  'tempmail.com',
  'guerrillamail.com',
  'throwaway.email',
  'fakeinbox.com',
  'temp-mail.org',
  'yopmail.com',
  'trashmail.com',
  'sharklasers.com',
  'guerrillamailblock.com',
  'grr.la',
  'mailnesia.com',
]);

@Injectable()
export class FraudDetectionService {
  private readonly logger = new Logger(FraudDetectionService.name);

  constructor(private readonly prisma: PrismaService) {}

  async check(params: {
    honeypot?: string;
    formFilledMs?: number;
    email?: string;
    phone?: string;
    fingerprint?: string;
    ip?: string;
    userAgent?: string;
  }): Promise<FraudCheckResult> {
    const factors: FraudCheckResult['factors'] = [];

    // 1. Honeypot — bots fill hidden fields
    if (params.honeypot) {
      factors.push({ name: 'honeypot', score: 100, detail: 'Hidden field filled' });
    }

    // 2. Timing — form filled too fast (<2s = bot)
    if (params.formFilledMs !== undefined && params.formFilledMs < 2000) {
      factors.push({
        name: 'timing',
        score: 50,
        detail: `Filled in ${params.formFilledMs}ms`,
      });
    }

    // 3. Disposable email
    if (params.email) {
      const domain = params.email.split('@')[1]?.toLowerCase();
      if (domain && DISPOSABLE_DOMAINS.has(domain)) {
        factors.push({ name: 'disposable_email', score: 40, detail: domain });
      }
    }

    // 4. Phone validation (basic: must be 10+ digits for RU)
    if (params.phone) {
      const digits = params.phone.replace(/\D/g, '');
      if (digits.length < 10 || digits.length > 15) {
        factors.push({
          name: 'invalid_phone',
          score: 30,
          detail: `${digits.length} digits`,
        });
      }
    }

    // 5. Fingerprint repeat (same fingerprint within 24h)
    if (params.fingerprint) {
      const dayAgo = new Date();
      dayAgo.setHours(dayAgo.getHours() - 24);

      const repeatCount = await this.prisma.crmDeal.count({
        where: {
          createdAt: { gte: dayAgo },
          metadata: {
            path: ['fingerprint'],
            equals: params.fingerprint,
          },
        },
      });

      if (repeatCount > 0) {
        factors.push({
          name: 'fingerprint_repeat',
          score: 30,
          detail: `${repeatCount} submissions in 24h`,
        });
      }
    }

    // 6. IP rate limit (3 submissions per 10 min)
    if (params.ip) {
      const tenMinAgo = new Date();
      tenMinAgo.setMinutes(tenMinAgo.getMinutes() - 10);

      const ipCount = await this.prisma.crmDeal.count({
        where: {
          createdAt: { gte: tenMinAgo },
          metadata: {
            path: ['ip'],
            equals: params.ip,
          },
        },
      });

      if (ipCount >= 3) {
        factors.push({
          name: 'ip_rate_limit',
          score: 20,
          detail: `${ipCount} submissions from ${params.ip} in 10min`,
        });
      }
    }

    const score = factors.reduce((sum, f) => sum + f.score, 0);
    let action: FraudCheckResult['action'] = 'allow';
    if (score >= 70) action = 'spam';
    else if (score >= 40) action = 'captcha';

    if (score > 0) {
      this.logger.log(
        `Fraud check: score=${score}, action=${action}, factors=${factors.map((f) => f.name).join(',')}`,
      );
    }

    return { score, factors, action };
  }
}
