import { logger } from '../../utils/logger';
import { FeatureGovernanceService } from '../governance/FeatureGovernanceService';
import db from '../../config/database';

/**
 * [AI_REC_01] 推荐系统服务
 * @description 基于用户行为的智能推荐，支持协同过滤、内容推荐、混合推荐
 */
export class RecommendationService {
  private static readonly USER_BEHAVIOR_TABLE = 'cf_ai_rec_user_behavior';
  private static readonly ITEM_ATTRIBUTES_TABLE = 'cf_ai_rec_item_attributes';
  private static readonly RECOMMENDATION_CACHE_TABLE = 'cf_ai_rec_cache';
  private static readonly ALGORITHM_CONFIG_TABLE = 'cf_ai_rec_algorithm_config';

  /**
   * 初始化表结构
   */
  static async initTable() {
    // 创建用户行为记录表
    const hasBehaviorTable = await db.schema.hasTable(this.USER_BEHAVIOR_TABLE);
    if (!hasBehaviorTable) {
      console.log(`📦 Creating ${this.USER_BEHAVIOR_TABLE} table...`);
      await db.schema.createTable(this.USER_BEHAVIOR_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable();
        table.string('user_id', 64).notNullable();
        table.string('item_id', 64).notNullable();
        table.enum('behavior_type', ['view', 'click', 'purchase', 'favorite']).notNullable();
        table.decimal('weight', 5, 2).defaultTo(1.0); // 行为权重
        table.timestamp('timestamp').defaultTo(db.fn.now());
        table.json('context'); // 上下文信息
        table.index(['tenant_id', 'user_id']);
        table.index(['tenant_id', 'item_id']);
        table.index(['tenant_id', 'timestamp']);
      });
    }

    // 创建商品属性表
    const hasItemTable = await db.schema.hasTable(this.ITEM_ATTRIBUTES_TABLE);
    if (!hasItemTable) {
      console.log(`📦 Creating ${this.ITEM_ATTRIBUTES_TABLE} table...`);
      await db.schema.createTable(this.ITEM_ATTRIBUTES_TABLE, (table) => {
        table.string('tenant_id', 64).notNullable();
        table.string('item_id', 64).notNullable();
        table.string('category', 100);
        table.decimal('price', 10, 2);
        table.json('tags'); // 商品标签
        table.integer('popularity').defaultTo(0); // 热度
        table.timestamp('created_at').defaultTo(db.fn.now());
        table.primary(['tenant_id', 'item_id']);
        table.index(['tenant_id', 'category']);
        table.index(['tenant_id', 'popularity']);
      });
    }

    // 创建推荐缓存表
    const hasCacheTable = await db.schema.hasTable(this.RECOMMENDATION_CACHE_TABLE);
    if (!hasCacheTable) {
      console.log(`📦 Creating ${this.RECOMMENDATION_CACHE_TABLE} table...`);
      await db.schema.createTable(this.RECOMMENDATION_CACHE_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable();
        table.string('user_id', 64).notNullable();
        table.json('recommendations').notNullable(); // 推荐商品ID列表
        table.string('algorithm', 50).notNullable(); // 使用的算法
        table.decimal('score', 5, 2); // 推荐质量评分
        table.timestamp('created_at').defaultTo(db.fn.now());
        table.timestamp('expires_at').notNullable();
        table.index(['tenant_id', 'user_id']);
        table.index(['tenant_id', 'algorithm']);
        table.index(['tenant_id', 'expires_at']);
      });
    }

    // 创建算法配置表
    const hasConfigTable = await db.schema.hasTable(this.ALGORITHM_CONFIG_TABLE);
    if (!hasConfigTable) {
      console.log(`📦 Creating ${this.ALGORITHM_CONFIG_TABLE} table...`);
      await db.schema.createTable(this.ALGORITHM_CONFIG_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable();
        table.string('algorithm_name', 50).notNullable();
        table.json('parameters').notNullable(); // 算法参数
        table.boolean('enabled').defaultTo(true);
        table.decimal('weight', 5, 2).defaultTo(1.0); // 算法权重
        table.timestamp('updated_at').defaultTo(db.fn.now());
        table.unique(['tenant_id', 'algorithm_name']);
      });
    }

    console.log('✅ RecommendationService tables initialized');
  }

  /**
   * 记录用户行为
   */
  static async recordUserBehavior(params: {
    tenantId: string;
    userId: string;
    itemId: string;
    behaviorType: 'view' | 'click' | 'purchase' | 'favorite';
    weight?: number;
    context?: any;
  }): Promise<void> {
    try {
      await db(this.USER_BEHAVIOR_TABLE).insert({
        tenant_id: params.tenantId,
        user_id: params.userId,
        item_id: params.itemId,
        behavior_type: params.behaviorType,
        weight: params.weight || this.getBehaviorWeight(params.behaviorType),
        context: params.context || {},
        timestamp: new Date()
      });

      logger.info(`[Recommendation] User behavior recorded: ${params.userId} -> ${params.itemId} (${params.behaviorType})`);
    } catch (error: any) {
      logger.error(`[Recommendation] Failed to record user behavior: ${error.message}`);
      throw error;
    }
  }

  /**
   * 获取行为权重
   */
  private static getBehaviorWeight(behaviorType: string): number {
    const weights: { [key: string]: number } = {
      'view': 1.0,
      'click': 2.0,
      'favorite': 3.0,
      'purchase': 5.0
    };
    return weights[behaviorType] || 1.0;
  }

  /**
   * 更新商品属性
   */
  static async updateItemAttributes(params: {
    tenantId: string;
    itemId: string;
    category?: string;
    price?: number;
    tags?: string[];
    popularity?: number;
  }): Promise<void> {
    try {
      const existing = await db(this.ITEM_ATTRIBUTES_TABLE)
        .where({ tenant_id: params.tenantId, item_id: params.itemId })
        .first();

      if (existing) {
        await db(this.ITEM_ATTRIBUTES_TABLE)
          .where({ tenant_id: params.tenantId, item_id: params.itemId })
          .update({
            category: params.category || existing.category,
            price: params.price || existing.price,
            tags: params.tags || existing.tags,
            popularity: params.popularity || existing.popularity
          });
      } else {
        await db(this.ITEM_ATTRIBUTES_TABLE).insert({
          tenant_id: params.tenantId,
          item_id: params.itemId,
          category: params.category || '',
          price: params.price || 0,
          tags: params.tags || [],
          popularity: params.popularity || 0
        });
      }

      logger.info(`[Recommendation] Item attributes updated: ${params.itemId}`);
    } catch (error: any) {
      logger.error(`[Recommendation] Failed to update item attributes: ${error.message}`);
      throw error;
    }
  }

  /**
   * 获取推荐结果
   */
  static async getRecommendations(params: {
    tenantId: string;
    userId: string;
    count?: number;
    algorithms?: string[];
    context?: any;
  }): Promise<{
    recommendations: string[];
    algorithm: string;
    score: number;
    fromCache: boolean;
  }> {
    const startTime = Date.now();
    const count = params.count || 10;
    
    try {
      // 1. 检查缓存
      const cached = await this.getCachedRecommendations(params.tenantId, params.userId);
      if (cached && cached.recommendations.length >= count) {
        logger.info(`[Recommendation] Using cached recommendations for user: ${params.userId}`);
        return {
          recommendations: cached.recommendations.slice(0, count),
          algorithm: cached.algorithm,
          score: cached.score,
          fromCache: true
        };
      }

      // 2. 获取用户行为历史
      const userHistory = await this.getUserBehaviorHistory(params.tenantId, params.userId, 100);
      
      // 3. 选择算法并计算推荐
      const algorithm = await this.selectAlgorithm(params.tenantId, userHistory, params.context);
      const recommendations = await this.calculateRecommendations(
        params.tenantId, params.userId, userHistory, algorithm, count
      );

      // 4. 缓存结果
      await this.cacheRecommendations(params.tenantId, params.userId, recommendations, algorithm);

      const processingTime = Date.now() - startTime;
      logger.info(`[Recommendation] Recommendations generated for user: ${params.userId}, algorithm: ${algorithm}, time: ${processingTime}ms`);

      return {
        recommendations: recommendations.map(r => r.itemId),
        algorithm,
        score: this.calculateRecommendationScore(recommendations),
        fromCache: false
      };

    } catch (error: any) {
      logger.error(`[Recommendation] Failed to get recommendations: ${error.message}`);
      // 降级策略：返回热门商品
      const fallback = await this.getPopularItems(params.tenantId, count);
      return {
        recommendations: fallback,
        algorithm: 'fallback_popular',
        score: 0.5,
        fromCache: false
      };
    }
  }

  /**
   * 获取缓存的推荐结果
   */
  private static async getCachedRecommendations(tenantId: string, userId: string): Promise<any> {
    const cache = await db(this.RECOMMENDATION_CACHE_TABLE)
      .where({ tenant_id: tenantId, user_id: userId })
      .where('expires_at', '>', new Date())
      .orderBy('created_at', 'desc')
      .first();

    return cache;
  }

  /**
   * 获取用户行为历史
   */
  private static async getUserBehaviorHistory(tenantId: string, userId: string, limit: number): Promise<any[]> {
    return await db(this.USER_BEHAVIOR_TABLE)
      .where({ tenant_id: tenantId, user_id: userId })
      .orderBy('timestamp', 'desc')
      .limit(limit);
  }

  /**
   * 选择推荐算法
   */
  private static async selectAlgorithm(tenantId: string, userHistory: any[], context?: any): Promise<string> {
    // 新用户使用内容推荐
    if (userHistory.length < 5) {
      return 'content_based';
    }

    // 活跃用户使用协同过滤
    if (userHistory.length >= 20) {
      return 'collaborative_filtering';
    }

    // 默认使用混合推荐
    return 'hybrid';
  }

  /**
   * 计算推荐结果
   */
  private static async calculateRecommendations(
    tenantId: string, 
    userId: string, 
    userHistory: any[], 
    algorithm: string, 
    count: number
  ): Promise<{itemId: string, score: number}[]> {
    switch (algorithm) {
      case 'content_based':
        return await this.contentBasedRecommendation(tenantId, userHistory, count);
      case 'collaborative_filtering':
        return await this.collaborativeFiltering(tenantId, userId, userHistory, count);
      case 'hybrid':
        return await this.hybridRecommendation(tenantId, userId, userHistory, count);
      default:
        return await this.getPopularItemsWithScore(tenantId, count);
    }
  }

  /**
   * 内容推荐算法
   */
  private static async contentBasedRecommendation(tenantId: string, userHistory: any[], count: number): Promise<{itemId: string, score: number}[]> {
    // 获取用户偏好的商品类别和标签
    const userPreferences = await this.analyzeUserPreferences(tenantId, userHistory);
    
    // 基于偏好推荐相似商品
    const allItems = await db(this.ITEM_ATTRIBUTES_TABLE)
      .where({ tenant_id: tenantId })
      .select('item_id', 'category', 'tags', 'popularity');

    const scoredItems = allItems.map(item => ({
      itemId: item.item_id,
      score: this.calculateContentSimilarity(userPreferences, item)
    }));

    return scoredItems
      .sort((a, b) => b.score - a.score)
      .slice(0, count);
  }

  /**
   * 协同过滤算法
   */
  private static async collaborativeFiltering(tenantId: string, userId: string, userHistory: any[], count: number): Promise<{itemId: string, score: number}[]> {
    // 基于用户-商品交互矩阵的推荐
    const similarUsers = await this.findSimilarUsers(tenantId, userId, userHistory);
    const recommendedItems = await this.getItemsFromSimilarUsers(tenantId, similarUsers, userHistory);
    
    return recommendedItems.slice(0, count);
  }

  /**
   * 混合推荐算法
   */
  private static async hybridRecommendation(tenantId: string, userId: string, userHistory: any[], count: number): Promise<{itemId: string, score: number}[]> {
    // 并行计算多种算法的推荐结果
    const [contentRecs, cfRecs] = await Promise.all([
      this.contentBasedRecommendation(tenantId, userHistory, count * 2),
      this.collaborativeFiltering(tenantId, userId, userHistory, count * 2)
    ]);

    // 合并并去重
    const merged = [...contentRecs, ...cfRecs];
    const uniqueItems = this.removeDuplicates(merged);
    
    // 重新评分和排序
    return uniqueItems
      .sort((a, b) => b.score - a.score)
      .slice(0, count);
  }

  /**
   * 分析用户偏好
   */
  private static async analyzeUserPreferences(tenantId: string, userHistory: any[]): Promise<any> {
    const preferences = {
      categories: new Map<string, number>(),
      tags: new Map<string, number>(),
      priceRange: { min: Infinity, max: 0 }
    };

    for (const behavior of userHistory) {
      const item = await db(this.ITEM_ATTRIBUTES_TABLE)
        .where({ tenant_id: tenantId, item_id: behavior.item_id })
        .first();

      if (item) {
        // 统计类别偏好
        if (item.category) {
          const current = preferences.categories.get(item.category) || 0;
          preferences.categories.set(item.category, current + behavior.weight);
        }

        // 统计标签偏好
        if (item.tags && Array.isArray(item.tags)) {
          item.tags.forEach((tag: string) => {
            const current = preferences.tags.get(tag) || 0;
            preferences.tags.set(tag, current + behavior.weight);
          });
        }

        // 统计价格偏好
        if (item.price) {
          preferences.priceRange.min = Math.min(preferences.priceRange.min, item.price);
          preferences.priceRange.max = Math.max(preferences.priceRange.max, item.price);
        }
      }
    }

    return preferences;
  }

  /**
   * 计算内容相似度
   */
  private static calculateContentSimilarity(userPreferences: any, item: any): number {
    let score = 0;
    
    // 类别匹配
    if (item.category && userPreferences.categories.has(item.category)) {
      score += userPreferences.categories.get(item.category) * 0.4;
    }
    
    // 标签匹配
    if (item.tags && Array.isArray(item.tags)) {
      item.tags.forEach((tag: string) => {
        if (userPreferences.tags.has(tag)) {
          score += userPreferences.tags.get(tag) * 0.3;
        }
      });
    }
    
    // 价格偏好匹配
    if (item.price && userPreferences.priceRange.min !== Infinity) {
      const priceScore = this.calculatePriceSimilarity(item.price, userPreferences.priceRange);
      score += priceScore * 0.3;
    }
    
    // 热度加成
    score += (item.popularity || 0) * 0.1;
    
    return score;
  }

  /**
   * 计算价格相似度
   */
  private static calculatePriceSimilarity(price: number, priceRange: any): number {
    const range = priceRange.max - priceRange.min;
    if (range === 0) return 1.0;
    
    const normalized = (price - priceRange.min) / range;
    return 1.0 - Math.abs(normalized - 0.5) * 2; // 偏好中间价格
  }

  /**
   * 查找相似用户
   */
  private static async findSimilarUsers(tenantId: string, userId: string, userHistory: any[]): Promise<string[]> {
    // 简化实现：返回最近活跃的用户
    const recentUsers = await db(this.USER_BEHAVIOR_TABLE)
      .where({ tenant_id: tenantId })
      .where('user_id', '!=', userId)
      .select('user_id')
      .distinct()
      .orderBy('timestamp', 'desc')
      .limit(100);

    return recentUsers.map(u => u.user_id);
  }

  /**
   * 从相似用户获取商品
   */
  private static async getItemsFromSimilarUsers(tenantId: string, similarUsers: string[], userHistory: any[]): Promise<{itemId: string, score: number}[]> {
    const userItemIds = new Set(userHistory.map(h => h.item_id));
    
    const itemsFromSimilarUsers = await db(this.USER_BEHAVIOR_TABLE)
      .where({ tenant_id: tenantId })
      .whereIn('user_id', similarUsers)
      .whereNotIn('item_id', Array.from(userItemIds))
      .select('item_id')
      .groupBy('item_id')
      .count('* as interaction_count')
      .orderBy('interaction_count', 'desc')
      .limit(50);

    return itemsFromSimilarUsers.map(item => ({
      itemId: String(item.item_id),
      score: parseInt(String(item.interaction_count)) / similarUsers.length
    }));
  }

  /**
   * 获取热门商品
   */
  private static async getPopularItems(tenantId: string, count: number): Promise<string[]> {
    const items = await db(this.ITEM_ATTRIBUTES_TABLE)
      .where({ tenant_id: tenantId })
      .orderBy('popularity', 'desc')
      .limit(count)
      .select('item_id');

    return items.map(item => item.item_id);
  }

  /**
   * 获取带分数的热门商品
   */
  private static async getPopularItemsWithScore(tenantId: string, count: number): Promise<{itemId: string, score: number}[]> {
    const items = await db(this.ITEM_ATTRIBUTES_TABLE)
      .where({ tenant_id: tenantId })
      .orderBy('popularity', 'desc')
      .limit(count)
      .select('item_id', 'popularity');

    const maxPopularity = Math.max(...items.map(item => item.popularity || 0));
    
    return items.map(item => ({
      itemId: item.item_id,
      score: maxPopularity > 0 ? (item.popularity || 0) / maxPopularity : 0.5
    }));
  }

  /**
   * 缓存推荐结果
   */
  private static async cacheRecommendations(tenantId: string, userId: string, recommendations: {itemId: string, score: number}[], algorithm: string): Promise<void> {
    const expiresAt = new Date(Date.now() + 30 * 60 * 1000); // 30分钟缓存
    
    await db(this.RECOMMENDATION_CACHE_TABLE).insert({
      tenant_id: tenantId,
      user_id: userId,
      recommendations: recommendations.map(r => r.itemId),
      algorithm,
      score: this.calculateRecommendationScore(recommendations),
      expires_at: expiresAt
    });
  }

  /**
   * 计算推荐质量评分
   */
  private static calculateRecommendationScore(recommendations: {itemId: string, score: number}[]): number {
    if (recommendations.length === 0) return 0;
    
    const avgScore = recommendations.reduce((sum, r) => sum + r.score, 0) / recommendations.length;
    const diversity = this.calculateDiversity(recommendations);
    
    return avgScore * 0.7 + diversity * 0.3;
  }

  /**
   * 计算推荐多样性
   */
  private static calculateDiversity(recommendations: {itemId: string, score: number}[]): number {
    if (recommendations.length <= 1) return 1.0;
    
    // 简化实现：基于分数分布的多样性
    const scores = recommendations.map(r => r.score);
    const variance = this.calculateVariance(scores);
    return Math.min(variance * 10, 1.0);
  }

  /**
   * 计算方差
   */
  private static calculateVariance(numbers: number[]): number {
    const mean = numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
    const squaredDiffs = numbers.map(num => Math.pow(num - mean, 2));
    return squaredDiffs.reduce((sum, diff) => sum + diff, 0) / numbers.length;
  }

  /**
   * 移除重复项
   */
  private static removeDuplicates(items: {itemId: string, score: number}[]): {itemId: string, score: number}[] {
    const seen = new Set();
    return items.filter(item => {
      if (seen.has(item.itemId)) {
        return false;
      }
      seen.add(item.itemId);
      return true;
    });
  }

  /**
   * 获取推荐效果统计
   */
  static async getRecommendationStats(tenantId: string): Promise<any> {
    const stats = await db(this.RECOMMENDATION_CACHE_TABLE)
      .where({ tenant_id: tenantId })
      .select(
        db.raw('COUNT(*) as total_recommendations'),
        db.raw('AVG(score) as avg_score'),
        db.raw('MAX(score) as max_score'),
        db.raw('MIN(score) as min_score'),
        db.raw('COUNT(DISTINCT user_id) as unique_users')
      )
      .first();

    return {
      totalRecommendations: stats.total_recommendations || 0,
      avgScore: parseFloat(stats.avg_score || 0).toFixed(3),
      maxScore: parseFloat(stats.max_score || 0).toFixed(3),
      minScore: parseFloat(stats.min_score || 0).toFixed(3),
      uniqueUsers: stats.unique_users || 0
    };
  }

  /**
   * 清理过期缓存
   */
  static async cleanupExpiredCache(tenantId: string): Promise<void> {
    await db(this.RECOMMENDATION_CACHE_TABLE)
      .where({ tenant_id: tenantId })
      .where('expires_at', '<', new Date())
      .delete();

    logger.info(`[Recommendation] Expired cache cleaned for tenant: ${tenantId}`);
  }
}