import { logger } from '../utils/logger';
import BlacklistDatabaseService from './BlacklistDatabaseService';
import BlacklistService from './BlacklistService';

export interface BuyerBehavior {
  buyer_id: string;
  platform: string;
  platform_buyer_id: string;
  order_count: number;
  return_rate: number;
  chargeback_rate: number;
  complaint_rate: number;
  refund_rate: number;
  average_order_value: number;
  purchase_frequency: number;
  review_score: number;
  suspicious_behavior: boolean;
  abnormal_activity: boolean;
  location_mismatch: boolean;
  payment_issues: number;
  account_age_days: number;
  device_changes: number;
  ip_changes: number;
  velocity_score: number;
  risk_indicators: string[];
  last_purchase_date: Date;
  first_purchase_date: Date;
}

export interface RiskAssessmentResult {
  buyer_id: string;
  platform: string;
  platform_buyer_id: string;
  risk_score: number;
  risk_level: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
  risk_factors: string[];
  recommendations: string[];
  assessment_date: Date;
  is_blacklisted: boolean;
  blacklist_reasons?: string[];
  confidence_score: number;
}

export interface RiskRule {
  id: string;
  name: string;
  description: string;
  condition: string;
  weight: number;
  threshold: number;
  action: 'ALERT' | 'BLOCK' | 'MONITOR';
  enabled: boolean;
  created_by: string;
  created_at: Date;
  updated_at: Date;
}

export interface RiskStatistics {
  total_assessments: number;
  high_risk_count: number;
  medium_risk_count: number;
  low_risk_count: number;
  critical_risk_count: number;
  blacklist_conversion_rate: number;
  false_positives: number;
  false_negatives: number;
  by_platform: Record<string, number>;
  by_risk_level: Record<string, number>;
  average_risk_score: number;
  risk_trend: {
    date: string;
    average_score: number;
  }[];
}

export interface RiskAssessmentRequest {
  tenant_id: string;
  shop_id: string;
  task_id?: string;
  trace_id: string;
  buyer_behavior: BuyerBehavior;
  include_blacklist_check: boolean;
  assessment_reason: string;
}

export default class RiskAssessmentService {
  private static instance: RiskAssessmentService;
  private blacklistService: BlacklistService;

  static getInstance(): RiskAssessmentService {
    if (!RiskAssessmentService.instance) {
      RiskAssessmentService.instance = new RiskAssessmentService();
    }
    return RiskAssessmentService.instance;
  }

  constructor() {
    this.blacklistService = BlacklistService.getInstance();
  }

  async initTables(): Promise<void> {
    // 初始化风险规则表
    const hasRiskRulesTable = await db.schema.hasTable('cf_risk_rule');
    if (!hasRiskRulesTable) {
      logger.info('[RiskAssessmentService] Creating cf_risk_rule table...');
      await db.schema.createTable('cf_risk_rule', (table) => {
        table.string('id', 36).primary();
        table.string('name', 255).notNullable();
        table.text('description').notNullable();
        table.text('condition').notNullable();
        table.decimal('weight', 5, 2).notNullable();
        table.decimal('threshold', 5, 2).notNullable();
        table.enum('action', ['ALERT', 'BLOCK', 'MONITOR']).notNullable();
        table.boolean('enabled').notNullable().defaultTo(true);
        table.string('created_by', 64).notNullable();
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
        table.datetime('updated_at').notNullable().defaultTo(db.fn.now());
      });
    }

    // 初始化风险评估记录表
    const hasRiskAssessmentsTable = await db.schema.hasTable('cf_risk_assessment');
    if (!hasRiskAssessmentsTable) {
      logger.info('[RiskAssessmentService] Creating cf_risk_assessment table...');
      await db.schema.createTable('cf_risk_assessment', (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('shop_id', 64).notNullable();
        table.string('task_id', 36);
        table.string('trace_id', 64).notNullable();
        table.string('buyer_id', 64).notNullable();
        table.string('platform', 64).notNullable().index();
        table.string('platform_buyer_id', 64).notNullable().index();
        table.decimal('risk_score', 5, 2).notNullable().index();
        table.enum('risk_level', ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).notNullable().index();
        table.json('risk_factors').notNullable();
        table.json('recommendations').notNullable();
        table.boolean('is_blacklisted').notNullable();
        table.json('blacklist_reasons');
        table.decimal('confidence_score', 5, 2).notNullable();
        table.text('assessment_reason').notNullable();
        table.json('buyer_behavior').notNullable();
        table.datetime('assessment_date').notNullable().defaultTo(db.fn.now());
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
      });
    }
  }

  async assessRisk(request: RiskAssessmentRequest): Promise<RiskAssessmentResult> {
    try {
      logger.info(`[RiskAssessmentService] Assessing risk for buyer: ${request.buyer_behavior.platform_buyer_id}, platform=${request.buyer_behavior.platform}, traceId=${request.trace_id}`);

      // 计算基础风险分数
      let riskScore = this.calculateBaseRiskScore(request.buyer_behavior);
      
      // 应用风险规则
      const { adjustedScore, riskFactors } = await this.applyRiskRules(request.buyer_behavior, riskScore);
      riskScore = adjustedScore;

      // 检查黑名单状态
      let isBlacklisted = false;
      let blacklistReasons: string[] = [];
      
      if (request.include_blacklist_check) {
        const blacklistCheck = await this.blacklistService.checkBlacklist(
          request.buyer_behavior.platform,
          request.buyer_behavior.platform_buyer_id,
          request.tenant_id
        );
        isBlacklisted = blacklistCheck.is_blacklisted;
        blacklistReasons = blacklistCheck.reasons || [];

        // 如果在黑名单中，提高风险分数
        if (isBlacklisted) {
          riskScore = Math.min(100, riskScore + 30);
          riskFactors.push('Buyer is in blacklist');
        }
      }

      // 确定风险等级
      const riskLevel = this.calculateRiskLevel(riskScore);

      // 生成建议
      const recommendations = this.generateRecommendations(riskLevel, riskFactors, isBlacklisted);

      // 计算置信度分数
      const confidenceScore = this.calculateConfidenceScore(request.buyer_behavior, riskFactors.length);

      // 保存评估记录
      await this.saveAssessmentRecord({
        ...request,
        risk_score: riskScore,
        risk_level: riskLevel,
        risk_factors: riskFactors,
        recommendations: recommendations,
        is_blacklisted: isBlacklisted,
        blacklist_reasons: blacklistReasons,
        confidence_score: confidenceScore
      });

      const result: RiskAssessmentResult = {
        buyer_id: request.buyer_behavior.buyer_id,
        platform: request.buyer_behavior.platform,
        platform_buyer_id: request.buyer_behavior.platform_buyer_id,
        risk_score: riskScore,
        risk_level: riskLevel,
        risk_factors: riskFactors,
        recommendations: recommendations,
        assessment_date: new Date(),
        is_blacklisted: isBlacklisted,
        blacklist_reasons: blacklistReasons,
        confidence_score: confidenceScore
      };

      logger.info(`[RiskAssessmentService] Risk assessment completed: score=${riskScore}, level=${riskLevel}, confidence=${confidenceScore}, traceId=${request.trace_id}`);
      return result;
    } catch (error: any) {
      logger.error(`[RiskAssessmentService] Failed to assess risk: ${error.message}, traceId=${request.trace_id}`);
      throw error;
    }
  }

  private calculateBaseRiskScore(behavior: BuyerBehavior): number {
    let score = 0;

    // 退货率 (0-20分)
    score += Math.min(20, behavior.return_rate * 20);

    // 退款率 (0-20分)
    score += Math.min(20, behavior.refund_rate * 20);

    // 拒付率 (0-25分)
    score += Math.min(25, behavior.chargeback_rate * 25);

    // 投诉率 (0-15分)
    score += Math.min(15, behavior.complaint_rate * 15);

    // 可疑行为 (0-10分)
    if (behavior.suspicious_behavior) score += 10;

    // 异常活动 (0-10分)
    if (behavior.abnormal_activity) score += 10;

    // 位置不匹配 (0-8分)
    if (behavior.location_mismatch) score += 8;

    // 支付问题 (0-5分 per issue)
    score += Math.min(15, behavior.payment_issues * 5);

    // 设备变更 (0-5分 per change)
    score += Math.min(10, behavior.device_changes * 2);

    // IP变更 (0-5分 per change)
    score += Math.min(10, behavior.ip_changes * 2);

    // 速度评分 (0-10分)
    score += Math.min(10, behavior.velocity_score);

    // 账户年龄 (新账户风险更高)
    if (behavior.account_age_days < 30) score += 10;
    else if (behavior.account_age_days < 90) score += 5;

    return Math.min(100, score);
  }

  private async applyRiskRules(behavior: BuyerBehavior, baseScore: number): Promise<{ adjustedScore: number; riskFactors: string[] }> {
    const riskFactors: string[] = [];
    let adjustedScore = baseScore;

    // 获取启用的风险规则
    const rules = await db('cf_risk_rule').where({ enabled: true });

    for (const rule of rules) {
      try {
        // 简单的规则评估逻辑
        if (this.evaluateRule(rule, behavior)) {
          adjustedScore = Math.min(100, adjustedScore + rule.weight);
          riskFactors.push(rule.name);
        }
      } catch (error) {
        logger.warn(`[RiskAssessmentService] Failed to evaluate rule ${rule.name}: ${error}`);
      }
    }

    return { adjustedScore, riskFactors };
  }

  private evaluateRule(rule: any, behavior: BuyerBehavior): boolean {
    // 简单的规则评估实现
    // 实际应用中可能需要更复杂的规则引擎
    switch (rule.name) {
      case 'High Return Rate':
        return behavior.return_rate > 0.3;
      case 'Chargeback History':
        return behavior.chargeback_rate > 0;
      case 'Suspicious Activity':
        return behavior.suspicious_behavior;
      case 'New Account':
        return behavior.account_age_days < 30;
      case 'Multiple Device Changes':
        return behavior.device_changes > 3;
      case 'Multiple IP Changes':
        return behavior.ip_changes > 3;
      default:
        return false;
    }
  }

  private calculateRiskLevel(score: number): 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' {
    if (score >= 80) return 'CRITICAL';
    if (score >= 60) return 'HIGH';
    if (score >= 30) return 'MEDIUM';
    return 'LOW';
  }

  private generateRecommendations(riskLevel: string, riskFactors: string[], isBlacklisted: boolean): string[] {
    const recommendations: string[] = [];

    switch (riskLevel) {
      case 'CRITICAL':
        recommendations.push('Block buyer immediately');
        recommendations.push('Add to blacklist');
        recommendations.push('Review all past transactions');
        recommendations.push('Consider legal action if fraud is suspected');
        break;
      case 'HIGH':
        recommendations.push('Place order on hold for manual review');
        recommendations.push('Request additional verification');
        recommendations.push('Limit order amount');
        recommendations.push('Monitor future transactions closely');
        break;
      case 'MEDIUM':
        recommendations.push('Monitor transaction closely');
        recommendations.push('Set lower order limits');
        recommendations.push('Require signature for delivery');
        break;
      case 'LOW':
        recommendations.push('Process order normally');
        recommendations.push('Continue monitoring');
        break;
    }

    if (isBlacklisted) {
      recommendations.push('Review blacklist entry details');
      recommendations.push('Consider permanent block if repeat offender');
    }

    if (riskFactors.includes('High Return Rate')) {
      recommendations.push('Consider restocking fees');
      recommendations.push('Review return policy compliance');
    }

    if (riskFactors.includes('Chargeback History')) {
      recommendations.push('Use secure payment methods');
      recommendations.push('Keep detailed transaction records');
    }

    return recommendations;
  }

  private calculateConfidenceScore(behavior: BuyerBehavior, riskFactorCount: number): number {
    let confidence = 50; // 基础置信度

    // 数据完整性提高置信度
    if (behavior.order_count > 0) confidence += 10;
    if (behavior.account_age_days > 30) confidence += 10;
    if (riskFactorCount > 0) confidence += 15;
    if (behavior.review_score > 0) confidence += 5;

    // 数据不足降低置信度
    if (behavior.order_count === 0) confidence -= 20;
    if (behavior.account_age_days < 7) confidence -= 15;

    return Math.max(10, Math.min(95, confidence));
  }

  private async saveAssessmentRecord(data: any): Promise<void> {
    const id = uuidv4();
    await db('cf_risk_assessment').insert({
      id,
      tenant_id: data.tenant_id,
      shop_id: data.shop_id,
      task_id: data.task_id,
      trace_id: data.trace_id,
      buyer_id: data.buyer_behavior.buyer_id,
      platform: data.buyer_behavior.platform,
      platform_buyer_id: data.buyer_behavior.platform_buyer_id,
      risk_score: data.risk_score,
      risk_level: data.risk_level,
      risk_factors: data.risk_factors,
      recommendations: data.recommendations,
      is_blacklisted: data.is_blacklisted,
      blacklist_reasons: data.blacklist_reasons,
      confidence_score: data.confidence_score,
      assessment_reason: data.assessment_reason,
      buyer_behavior: data.buyer_behavior,
      assessment_date: new Date(),
      created_at: new Date()
    });
  }

  async getRiskAssessments(tenantId: string, filter?: {
    platform?: string;
    risk_level?: string;
    start_date?: Date;
    end_date?: Date;
    limit?: number;
    offset?: number;
  }): Promise<{
    assessments: any[];
    total: number;
  }> {
    try {
      let query = db('cf_risk_assessment').where({ tenant_id: tenantId });

      if (filter) {
        if (filter.platform) {
          query = query.where({ platform: filter.platform });
        }
        if (filter.risk_level) {
          query = query.where({ risk_level: filter.risk_level });
        }
        if (filter.start_date) {
          query = query.where('assessment_date', '>=', filter.start_date);
        }
        if (filter.end_date) {
          query = query.where('assessment_date', '<=', filter.end_date);
        }
      }

      const total = await query.count('id as count').first();
      const assessments = await query
        .orderBy('assessment_date', 'desc')
        .limit(filter?.limit || 100)
        .offset(filter?.offset || 0);

      return {
        assessments,
        total: total ? parseInt(total.count as string) : 0
      };
    } catch (error: any) {
      logger.error(`[RiskAssessmentService] Failed to get risk assessments: ${error.message}`);
      return { assessments: [], total: 0 };
    }
  }

  async getRiskStatistics(tenantId: string, days: number = 30): Promise<RiskStatistics> {
    try {
      const startDate = new Date();
      startDate.setDate(startDate.getDate() - days);

      const totalAssessments = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId })
        .where('assessment_date', '>=', startDate)
        .count('id as count')
        .first();

      const highRiskCount = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId, risk_level: 'HIGH' })
        .where('assessment_date', '>=', startDate)
        .count('id as count')
        .first();

      const mediumRiskCount = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId, risk_level: 'MEDIUM' })
        .where('assessment_date', '>=', startDate)
        .count('id as count')
        .first();

      const lowRiskCount = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId, risk_level: 'LOW' })
        .where('assessment_date', '>=', startDate)
        .count('id as count')
        .first();

      const criticalRiskCount = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId, risk_level: 'CRITICAL' })
        .where('assessment_date', '>=', startDate)
        .count('id as count')
        .first();

      const blacklistConversion = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId, is_blacklisted: true })
        .where('assessment_date', '>=', startDate)
        .count('id as count')
        .first();

      const byPlatform = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId })
        .where('assessment_date', '>=', startDate)
        .select('platform', db.raw('count(*) as count'))
        .groupBy('platform');

      const byRiskLevel = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId })
        .where('assessment_date', '>=', startDate)
        .select('risk_level', db.raw('count(*) as count'))
        .groupBy('risk_level');

      const averageScore = await db('cf_risk_assessment')
        .where({ tenant_id: tenantId })
        .where('assessment_date', '>=', startDate)
        .avg('risk_score as avg_score')
        .first();

      // 生成风险趋势数据
      const riskTrend = [];
      for (let i = days - 1; i >= 0; i--) {
        const date = new Date();
        date.setDate(date.getDate() - i);
        const dateStr = date.toISOString().split('T')[0];
        
        const dayStart = new Date(date);
        dayStart.setHours(0, 0, 0, 0);
        
        const dayEnd = new Date(date);
        dayEnd.setHours(23, 59, 59, 999);

        const dayAverage = await db('cf_risk_assessment')
          .where({ tenant_id: tenantId })
          .whereBetween('assessment_date', [dayStart, dayEnd])
          .avg('risk_score as avg_score')
          .first();

        riskTrend.push({
          date: dateStr,
          average_score: dayAverage?.avg_score ? parseFloat(dayAverage.avg_score as string) : 0
        });
      }

      const total = totalAssessments ? parseInt(totalAssessments.count as string) : 0;
      const blacklistCount = blacklistConversion ? parseInt(blacklistConversion.count as string) : 0;

      return {
        total_assessments: total,
        high_risk_count: highRiskCount ? parseInt(highRiskCount.count as string) : 0,
        medium_risk_count: mediumRiskCount ? parseInt(mediumRiskCount.count as string) : 0,
        low_risk_count: lowRiskCount ? parseInt(lowRiskCount.count as string) : 0,
        critical_risk_count: criticalRiskCount ? parseInt(criticalRiskCount.count as string) : 0,
        blacklist_conversion_rate: total > 0 ? (blacklistCount / total) * 100 : 0,
        false_positives: 0, // 需要额外逻辑计算
        false_negatives: 0, // 需要额外逻辑计算
        by_platform: byPlatform.reduce((acc, item) => {
          acc[item.platform] = parseInt(item.count as string);
          return acc;
        }, {} as Record<string, number>),
        by_risk_level: byRiskLevel.reduce((acc, item) => {
          acc[item.risk_level] = parseInt(item.count as string);
          return acc;
        }, {} as Record<string, number>),
        average_risk_score: averageScore?.avg_score ? parseFloat(averageScore.avg_score as string) : 0,
        risk_trend: riskTrend
      };
    } catch (error: any) {
      logger.error(`[RiskAssessmentService] Failed to get risk statistics: ${error.message}`);
      return {
        total_assessments: 0,
        high_risk_count: 0,
        medium_risk_count: 0,
        low_risk_count: 0,
        critical_risk_count: 0,
        blacklist_conversion_rate: 0,
        false_positives: 0,
        false_negatives: 0,
        by_platform: {},
        by_risk_level: {},
        average_risk_score: 0,
        risk_trend: []
      };
    }
  }

  async createRiskRule(rule: Omit<RiskRule, 'id' | 'created_at' | 'updated_at'>): Promise<RiskRule> {
    try {
      const id = uuidv4();
      const now = new Date();
      
      const newRule: RiskRule = {
        ...rule,
        id,
        created_at: now,
        updated_at: now
      };

      await db('cf_risk_rule').insert(newRule);
      logger.info(`[RiskAssessmentService] Risk rule created: id=${id}, name=${rule.name}`);
      return newRule;
    } catch (error: any) {
      logger.error(`[RiskAssessmentService] Failed to create risk rule: ${error.message}`);
      throw error;
    }
  }

  async updateRiskRule(id: string, updates: Partial<RiskRule>): Promise<boolean> {
    try {
      const result = await db('cf_risk_rule')
        .where({ id })
        .update({
          ...updates,
          updated_at: new Date()
        });

      if (result > 0) {
        logger.info(`[RiskAssessmentService] Risk rule updated: id=${id}`);
      }
      return result > 0;
    } catch (error: any) {
      logger.error(`[RiskAssessmentService] Failed to update risk rule: ${error.message}`);
      return false;
    }
  }

  async getRiskRules(): Promise<RiskRule[]> {
    try {
      const rules = await db('cf_risk_rule').where({ enabled: true }).orderBy('weight', 'desc');
      return rules as RiskRule[];
    } catch (error: any) {
      logger.error(`[RiskAssessmentService] Failed to get risk rules: ${error.message}`);
      return [];
    }
  }
}

// 导入必要的依赖
import db from '../config/database';
import { v4 as uuidv4 } from 'uuid';
