import { Injectable, Inject, Logger } from '@nestjs/common';
import { LeaderboardType, LeaderboardPeriod } from '../../domain/value-objects';
import { LeaderboardConfig } from '../../domain/aggregates/leaderboard-config/leaderboard-config.aggregate';
import { LeaderboardRanking } from '../../domain/aggregates/leaderboard-ranking/leaderboard-ranking.aggregate';
import {
  ILeaderboardRankingRepository,
  LEADERBOARD_RANKING_REPOSITORY,
} from '../../domain/repositories/leaderboard-ranking.repository.interface';
import {
  ILeaderboardConfigRepository,
  LEADERBOARD_CONFIG_REPOSITORY,
} from '../../domain/repositories/leaderboard-config.repository.interface';
import { LeaderboardCalculationService } from '../../domain/services/leaderboard-calculation.service';
import { VirtualRankingGeneratorService } from '../../domain/services/virtual-ranking-generator.service';
import { RankingMergerService } from '../../domain/services/ranking-merger.service';
import { LeaderboardCacheService } from '../../infrastructure/cache/leaderboard-cache.service';
import { EventPublisherService } from '../../infrastructure/messaging/event-publisher.service';
import { LeaderboardRefreshedEvent } from '../../domain/events/leaderboard-refreshed.event';

/**
 * 龙虎榜应用服务
 *
 * 编排领域服务，实现用例
 */
@Injectable()
export class LeaderboardApplicationService {
  private readonly logger = new Logger(LeaderboardApplicationService.name);

  constructor(
    @Inject(LEADERBOARD_RANKING_REPOSITORY)
    private readonly rankingRepository: ILeaderboardRankingRepository,
    @Inject(LEADERBOARD_CONFIG_REPOSITORY)
    private readonly configRepository: ILeaderboardConfigRepository,
    private readonly calculationService: LeaderboardCalculationService,
    private readonly virtualRankingGenerator: VirtualRankingGeneratorService,
    private readonly rankingMerger: RankingMergerService,
    private readonly cacheService: LeaderboardCacheService,
    private readonly eventPublisher: EventPublisherService,
  ) {}

  /**
   * 刷新榜单
   *
   * 完整刷新流程：
   * 1. 检查榜单是否启用
   * 2. 计算真实用户排名
   * 3. 生成虚拟排名（如果启用）
   * 4. 合并排名
   * 5. 保存到数据库
   * 6. 更新缓存
   * 7. 发布事件
   */
  async refreshLeaderboard(type: LeaderboardType): Promise<void> {
    const config = await this.configRepository.getGlobalConfig();
    const period = LeaderboardPeriod.current(type);

    // 1. 检查榜单是否启用
    if (!config.isLeaderboardEnabled(type)) {
      this.logger.log(`${type} 榜单未启用，跳过刷新`);
      return;
    }

    this.logger.log(`开始刷新 ${type} 榜单...`);

    try {
      // 2. 计算真实用户排名
      const realRankings = await this.calculationService.calculateRankings(
        type,
        config.displayLimit,
      );

      // 3. 生成虚拟排名（如果启用）
      let virtualRankings: LeaderboardRanking[] = [];
      if (config.virtualRankingEnabled && config.virtualAccountCount > 0) {
        const topRealScore = realRankings.length > 0
          ? realRankings[0].score.effectiveScore
          : 0;

        virtualRankings = await this.virtualRankingGenerator.generateVirtualRankings({
          type,
          count: config.virtualAccountCount,
          topRealScore,
        });
      }

      // 4. 合并排名
      const mergedRankings = this.rankingMerger.mergeRankings(
        virtualRankings,
        realRankings,
        config.displayLimit,
      );

      // 5. 删除旧排名并保存新排名
      await this.rankingRepository.deleteByTypeAndPeriod(type, period.key);
      if (mergedRankings.length > 0) {
        await this.rankingRepository.saveAll(mergedRankings);
      }

      // 6. 更新缓存
      await this.cacheService.invalidateLeaderboard(type, period.key);
      await this.cacheService.cacheLeaderboard(
        type,
        period.key,
        mergedRankings.map((r) => this.toRankingDto(r)),
      );

      // 7. 发布事件
      const topScore = realRankings.length > 0
        ? realRankings[0].score.effectiveScore
        : 0;

      await this.eventPublisher.publish(
        new LeaderboardRefreshedEvent({
          leaderboardType: type,
          periodKey: period.key,
          totalParticipants: realRankings.length,
          topScore,
          refreshedAt: new Date(),
        }),
      );

      this.logger.log(
        `${type} 榜单刷新完成: ${realRankings.length} 真实用户, ${virtualRankings.length} 虚拟用户`,
      );
    } catch (error) {
      this.logger.error(`${type} 榜单刷新失败`, error);
      throw error;
    }
  }

  /**
   * 获取榜单列表
   */
  async getLeaderboard(
    type: LeaderboardType,
    limit?: number,
  ): Promise<any[]> {
    const config = await this.configRepository.getGlobalConfig();
    const period = LeaderboardPeriod.current(type);
    const displayLimit = limit || config.displayLimit;

    // 先尝试从缓存获取
    const cached = await this.cacheService.getCachedLeaderboard(type, period.key);
    if (cached) {
      return cached.slice(0, displayLimit);
    }

    // 缓存未命中，从数据库获取
    const rankings = await this.rankingRepository.findByTypeAndPeriod(
      type,
      period.key,
      { limit: displayLimit, includeVirtual: true },
    );

    const result = rankings.map((r) => this.toRankingDto(r));

    // 更新缓存
    await this.cacheService.cacheLeaderboard(type, period.key, result);

    return result;
  }

  /**
   * 获取用户排名
   */
  async getUserRanking(type: LeaderboardType, userId: bigint): Promise<any | null> {
    const period = LeaderboardPeriod.current(type);

    // 先尝试从缓存获取
    const cached = await this.cacheService.getCachedUserRanking(type, period.key, userId);
    if (cached) {
      return cached;
    }

    // 从数据库获取
    const ranking = await this.rankingRepository.findUserRanking(type, period.key, userId);
    if (!ranking) {
      return null;
    }

    const result = this.toRankingDto(ranking);

    // 更新缓存
    await this.cacheService.cacheUserRanking(type, period.key, userId, result);

    return result;
  }

  /**
   * 获取我在各榜单的排名
   */
  async getMyRankings(userId: bigint): Promise<Record<string, any>> {
    const result: Record<string, any> = {};

    for (const type of Object.values(LeaderboardType)) {
      result[type] = await this.getUserRanking(type as LeaderboardType, userId);
    }

    return result;
  }

  /**
   * 保存榜单快照
   */
  async saveSnapshot(type: LeaderboardType): Promise<void> {
    const period = LeaderboardPeriod.current(type);
    this.logger.log(`保存 ${type} 榜单快照: ${period.key}`);

    // TODO: 实现快照保存逻辑
  }

  /**
   * 获取配置
   */
  async getConfig(): Promise<LeaderboardConfig> {
    return this.configRepository.getGlobalConfig();
  }

  /**
   * 更新配置
   */
  async updateConfig(config: LeaderboardConfig): Promise<void> {
    await this.configRepository.save(config);

    // 发布配置更新事件
    for (const event of config.domainEvents) {
      await this.eventPublisher.publish(event);
    }
    config.clearDomainEvents();
  }

  private toRankingDto(ranking: LeaderboardRanking): any {
    return {
      id: ranking.id?.toString(),
      leaderboardType: ranking.leaderboardType,
      periodKey: ranking.periodKey,
      userId: ranking.userId.toString(),
      isVirtual: ranking.isVirtual,
      rankPosition: ranking.rankPosition.value,
      displayPosition: ranking.displayPosition.value,
      previousRank: ranking.previousRank?.value || null,
      rankChange: ranking.rankChange,
      totalTeamPlanting: ranking.score.totalTeamPlanting,
      maxDirectTeamPlanting: ranking.score.maxDirectTeamPlanting,
      effectiveScore: ranking.score.effectiveScore,
      nickname: ranking.userSnapshot.nickname,
      avatar: ranking.userSnapshot.getAvatarOrDefault(),
      accountNo: ranking.userSnapshot.accountNo,
      calculatedAt: ranking.calculatedAt.toISOString(),
    };
  }
}
