import { DomainEvent } from '../../events/domain-event.base';
import { LeaderboardType } from '../../value-objects/leaderboard-type.enum';
import { LeaderboardPeriod } from '../../value-objects/leaderboard-period.vo';
import { RankingScore } from '../../value-objects/ranking-score.vo';
import { RankPosition } from '../../value-objects/rank-position.vo';
import { UserSnapshot } from '../../value-objects/user-snapshot.vo';

/**
 * 龙虎榜排名聚合根
 *
 * 不变式:
 * 1. 同一榜单内排名必须唯一且连续
 * 2. 虚拟账户不参与真实排名计算
 * 3. 有效分值 = 团队总认种 - 最大单个直推团队认种
 */
export class LeaderboardRanking {
  private _id: bigint | null = null;
  private readonly _leaderboardType: LeaderboardType;
  private readonly _period: LeaderboardPeriod;
  private readonly _userId: bigint;
  private readonly _isVirtual: boolean;
  private _rankPosition: RankPosition;
  private _displayPosition: RankPosition;
  private _previousRank: RankPosition | null;
  private _score: RankingScore;
  private readonly _userSnapshot: UserSnapshot;
  private readonly _calculatedAt: Date;

  private _domainEvents: DomainEvent[] = [];

  private constructor(
    leaderboardType: LeaderboardType,
    period: LeaderboardPeriod,
    userId: bigint,
    isVirtual: boolean,
    rankPosition: RankPosition,
    displayPosition: RankPosition,
    previousRank: RankPosition | null,
    score: RankingScore,
    userSnapshot: UserSnapshot,
    calculatedAt: Date,
  ) {
    this._leaderboardType = leaderboardType;
    this._period = period;
    this._userId = userId;
    this._isVirtual = isVirtual;
    this._rankPosition = rankPosition;
    this._displayPosition = displayPosition;
    this._previousRank = previousRank;
    this._score = score;
    this._userSnapshot = userSnapshot;
    this._calculatedAt = calculatedAt;
  }

  // ============ Getters ============
  get id(): bigint | null { return this._id; }
  get leaderboardType(): LeaderboardType { return this._leaderboardType; }
  get period(): LeaderboardPeriod { return this._period; }
  get periodKey(): string { return this._period.key; }
  get userId(): bigint { return this._userId; }
  get isVirtual(): boolean { return this._isVirtual; }
  get rankPosition(): RankPosition { return this._rankPosition; }
  get displayPosition(): RankPosition { return this._displayPosition; }
  get previousRank(): RankPosition | null { return this._previousRank; }
  get score(): RankingScore { return this._score; }
  get userSnapshot(): UserSnapshot { return this._userSnapshot; }
  get calculatedAt(): Date { return this._calculatedAt; }
  get domainEvents(): DomainEvent[] { return [...this._domainEvents]; }

  get rankChange(): number {
    return this._displayPosition.calculateChange(this._previousRank);
  }

  // ============ 工厂方法 ============

  /**
   * 创建真实用户排名
   */
  static createRealRanking(params: {
    leaderboardType: LeaderboardType;
    period: LeaderboardPeriod;
    userId: bigint;
    rankPosition: number;
    displayPosition: number;
    previousRank: number | null;
    totalTeamPlanting: number;
    maxDirectTeamPlanting: number;
    userSnapshot: UserSnapshot;
  }): LeaderboardRanking {
    const score = RankingScore.calculate(
      params.totalTeamPlanting,
      params.maxDirectTeamPlanting,
    );

    return new LeaderboardRanking(
      params.leaderboardType,
      params.period,
      params.userId,
      false,
      RankPosition.create(params.rankPosition),
      RankPosition.create(params.displayPosition),
      params.previousRank ? RankPosition.create(params.previousRank) : null,
      score,
      params.userSnapshot,
      new Date(),
    );
  }

  /**
   * 创建虚拟用户排名
   */
  static createVirtualRanking(params: {
    leaderboardType: LeaderboardType;
    period: LeaderboardPeriod;
    virtualAccountId: bigint;
    displayPosition: number;
    generatedScore: number;
    displayName: string;
    avatar: string | null;
  }): LeaderboardRanking {
    const userSnapshot = UserSnapshot.create({
      userId: params.virtualAccountId,
      nickname: params.displayName,
      avatar: params.avatar,
    });

    return new LeaderboardRanking(
      params.leaderboardType,
      params.period,
      params.virtualAccountId,
      true,
      RankPosition.create(params.displayPosition),  // 虚拟账户的实际排名等于显示排名
      RankPosition.create(params.displayPosition),
      null,
      RankingScore.fromRaw(params.generatedScore, 0, params.generatedScore),
      userSnapshot,
      new Date(),
    );
  }

  // ============ 领域行为 ============

  /**
   * 更新显示排名（虚拟排名插入后调整）
   */
  updateDisplayPosition(newDisplayPosition: number): void {
    this._displayPosition = RankPosition.create(newDisplayPosition);
  }

  /**
   * 是否在显示范围内
   */
  isWithinDisplayLimit(limit: number): boolean {
    return this._displayPosition.isTop(limit);
  }

  /**
   * 获取排名变化描述
   */
  getRankChangeDescription(): string {
    return this._displayPosition.getChangeDescription(this._previousRank);
  }

  setId(id: bigint): void {
    this._id = id;
  }

  clearDomainEvents(): void {
    this._domainEvents = [];
  }

  protected addDomainEvent(event: DomainEvent): void {
    this._domainEvents.push(event);
  }

  // ============ 重建 ============

  static reconstitute(data: {
    id: bigint;
    leaderboardType: LeaderboardType;
    periodKey: string;
    periodStartAt: Date;
    periodEndAt: Date;
    userId: bigint;
    isVirtual: boolean;
    rankPosition: number;
    displayPosition: number;
    previousRank: number | null;
    totalTeamPlanting: number;
    maxDirectTeamPlanting: number;
    effectiveScore: number;
    userSnapshot: Record<string, any>;
    calculatedAt: Date;
  }): LeaderboardRanking {
    const period = LeaderboardPeriod.fromData(
      data.leaderboardType,
      data.periodKey,
      data.periodStartAt,
      data.periodEndAt,
    );

    const ranking = new LeaderboardRanking(
      data.leaderboardType,
      period,
      data.userId,
      data.isVirtual,
      RankPosition.create(data.rankPosition),
      RankPosition.create(data.displayPosition),
      data.previousRank ? RankPosition.create(data.previousRank) : null,
      RankingScore.fromRaw(
        data.totalTeamPlanting,
        data.maxDirectTeamPlanting,
        data.effectiveScore,
      ),
      UserSnapshot.fromJson(data.userSnapshot),
      data.calculatedAt,
    );
    ranking._id = data.id;
    return ranking;
  }
}
