import { Injectable, Inject, Logger } from '@nestjs/common';
import {
  REFERRAL_RELATIONSHIP_REPOSITORY,
  IReferralRelationshipRepository,
  TEAM_STATISTICS_REPOSITORY,
  ITeamStatisticsRepository,
  ReferralChainService,
  TeamStatisticsUpdatedEvent,
} from '../../domain';
import { EventPublisherService } from '../../infrastructure';
import { UpdateTeamStatisticsCommand } from '../commands';
import {
  GetProvinceCityDistributionQuery,
  ProvinceCityDistributionResult,
} from '../queries';

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

  constructor(
    @Inject(REFERRAL_RELATIONSHIP_REPOSITORY)
    private readonly referralRepo: IReferralRelationshipRepository,
    @Inject(TEAM_STATISTICS_REPOSITORY)
    private readonly teamStatsRepo: ITeamStatisticsRepository,
    private readonly referralChainService: ReferralChainService,
    private readonly eventPublisher: EventPublisherService,
  ) {}

  /**
   * 处理认种事件 - 更新用户及其所有上级的团队统计
   */
  async handlePlantingEvent(command: UpdateTeamStatisticsCommand): Promise<void> {
    // 使用 accountSequence 获取用户的推荐关系
    const relationship = await this.referralRepo.findByAccountSequence(command.accountSequence);
    if (!relationship) {
      this.logger.warn(`User with accountSequence ${command.accountSequence} has no referral relationship`);
      return;
    }

    const userId = relationship.userId;

    // 更新用户自己的个人认种统计
    const userStats = await this.teamStatsRepo.findByUserId(userId);
    if (userStats) {
      userStats.addPersonalPlanting(command.plantingCount, command.provinceCode, command.cityCode);
      await this.teamStatsRepo.save(userStats);
      await this.eventPublisher.publishDomainEvents(userStats.domainEvents);
      userStats.clearDomainEvents();
    }

    // 获取所有需要更新的上级
    const ancestors = relationship.getAllAncestorIds();
    if (ancestors.length === 0) return;

    // 准备批量更新数据
    const updates: Array<{
      userId: bigint;
      countDelta: number;
      provinceCode: string;
      cityCode: string;
      fromDirectReferralId?: bigint;
    }> = [];

    // 第一级上级 (直接推荐人) 的 fromDirectReferralId 是当前用户
    // 第二级及以上的 fromDirectReferralId 是第一级上级

    for (let i = 0; i < ancestors.length; i++) {
      const ancestorId = ancestors[i];
      updates.push({
        userId: ancestorId,
        countDelta: command.plantingCount,
        provinceCode: command.provinceCode,
        cityCode: command.cityCode,
        fromDirectReferralId: i === 0 ? userId : ancestors[0],
      });
    }

    // 批量更新
    await this.teamStatsRepo.batchUpdateTeamCounts(updates);

    // 批量更新后，为所有更新的祖先发布 TeamStatisticsUpdatedEvent
    // 这是为了让 authorization-service 可以在统计数据更新后进行升级检查
    const updatedStats = await this.teamStatsRepo.findByUserIds(ancestors);
    const events = updatedStats.map(
      (stats) =>
        new TeamStatisticsUpdatedEvent(
          stats.userId,
          stats.accountSequence,
          stats.teamPlantingCount,  // totalTeamCount 即团队认种数
          stats.directReferralCount,
          stats.leaderboardScore,
          'planting_added',
        ),
    );

    if (events.length > 0) {
      await this.eventPublisher.publishDomainEvents(events);
      this.logger.log(`Published ${events.length} TeamStatisticsUpdatedEvent for ancestors`);
    }

    this.logger.log(
      `Updated team statistics for ${ancestors.length} ancestors of accountSequence ${command.accountSequence}`,
    );
  }

  /**
   * 获取省市分布统计
   */
  async getProvinceCityDistribution(
    query: GetProvinceCityDistributionQuery,
  ): Promise<ProvinceCityDistributionResult> {
    const stats = await this.teamStatsRepo.findByUserId(query.userId);
    if (!stats) {
      return {
        provinces: [],
        totalCount: 0,
      };
    }

    const distribution = stats.provinceCityDistribution;
    const allData = distribution.getAll();

    // 按省分组
    const provinceMap = new Map<string, { total: number; cities: Map<string, number> }>();
    for (const item of allData) {
      if (!provinceMap.has(item.provinceCode)) {
        provinceMap.set(item.provinceCode, { total: 0, cities: new Map() });
      }
      const province = provinceMap.get(item.provinceCode)!;
      province.total += item.count;
      province.cities.set(item.cityCode, item.count);
    }

    const provinces = Array.from(provinceMap.entries()).map(([provinceCode, data]) => ({
      provinceCode,
      total: data.total,
      cities: Array.from(data.cities.entries()).map(([cityCode, count]) => ({
        cityCode,
        count,
      })),
    }));

    return {
      provinces,
      totalCount: distribution.getTotal(),
    };
  }
}
