import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { MiningAccountRepository } from '../../infrastructure/persistence/repositories/mining-account.repository';
import { MiningAccountAggregate } from '../../domain/aggregates/mining-account.aggregate';
import { ShareAmount } from '../../domain/value-objects/share-amount.vo';
import { RedisService } from '../../infrastructure/redis/redis.service';

interface ContributionData {
  accountSequence: string;
  contribution: string;
}

/**
 * 算力同步服务
 * 从 contribution-service 同步用户算力数据
 */
@Injectable()
export class ContributionSyncService {
  private readonly logger = new Logger(ContributionSyncService.name);
  private readonly LOCK_KEY = 'mining:sync:lock';

  constructor(
    private readonly miningAccountRepository: MiningAccountRepository,
    private readonly redis: RedisService,
    private readonly configService: ConfigService,
  ) {}

  /**
   * 处理算力计算完成事件
   */
  async handleContributionCalculated(data: {
    accountSequence: string;
    personalContribution: string;
    calculatedAt: string;
  }): Promise<void> {
    try {
      // 获取或创建挖矿账户
      let account = await this.miningAccountRepository.findByAccountSequence(data.accountSequence);

      if (!account) {
        account = MiningAccountAggregate.create(data.accountSequence);
      }

      // 更新算力
      const contribution = new ShareAmount(data.personalContribution);
      account.updateContribution(contribution);

      await this.miningAccountRepository.save(account);

      this.logger.debug(
        `Updated contribution for ${data.accountSequence}: ${data.personalContribution}`,
      );
    } catch (error) {
      this.logger.error(`Failed to handle contribution calculated event`, error);
      throw error;
    }
  }

  /**
   * 处理每日快照创建事件
   * 批量同步所有用户的算力
   */
  async handleDailySnapshotCreated(data: {
    snapshotId: string;
    snapshotDate: string;
    totalContribution: string;
    activeAccounts: number;
  }): Promise<void> {
    const lockValue = await this.redis.acquireLock(this.LOCK_KEY, 300);
    if (!lockValue) {
      this.logger.debug('Another instance is syncing contributions');
      return;
    }

    try {
      this.logger.log(`Starting contribution sync for snapshot ${data.snapshotId}`);

      // 调用 contribution-service API 批量获取用户算力
      const contributionServiceUrl = this.configService.get<string>(
        'CONTRIBUTION_SERVICE_URL',
        'http://localhost:3020',
      );

      let page = 1;
      const pageSize = 1000;
      let syncedCount = 0;

      while (true) {
        // 获取算力数据
        const response = await this.fetchContributionRatios(
          contributionServiceUrl,
          data.snapshotDate,
          page,
          pageSize,
        );

        if (!response || !response.data || response.data.length === 0) break;

        // 批量更新
        for (const item of response.data) {
          await this.syncAccountContribution(item.accountSequence, item.contribution);
          syncedCount++;
        }

        if (response.data.length < pageSize) break;
        page++;
      }

      this.logger.log(`Contribution sync completed: synced ${syncedCount} accounts`);
    } catch (error) {
      this.logger.error('Failed to sync contributions from daily snapshot', error);
    } finally {
      await this.redis.releaseLock(this.LOCK_KEY, lockValue);
    }
  }

  /**
   * 从 contribution-service 获取算力数据
   */
  private async fetchContributionRatios(
    baseUrl: string,
    snapshotDate: string,
    page: number,
    pageSize: number,
  ): Promise<{ data: ContributionData[]; total: number } | null> {
    try {
      const url = `${baseUrl}/api/v2/snapshots/${snapshotDate}/ratios?page=${page}&pageSize=${pageSize}`;
      const response = await fetch(url);

      if (!response.ok) {
        this.logger.error(`Failed to fetch contribution ratios: ${response.status}`);
        return null;
      }

      const result = await response.json();
      // API 直接返回 { data: [...], total, totalContribution }
      return result;
    } catch (error) {
      this.logger.error('Failed to fetch contribution ratios', error);
      return null;
    }
  }

  /**
   * 同步单个账户的算力
   */
  private async syncAccountContribution(accountSequence: string, contribution: string): Promise<void> {
    let account = await this.miningAccountRepository.findByAccountSequence(accountSequence);

    if (!account) {
      account = MiningAccountAggregate.create(accountSequence);
    }

    account.updateContribution(new ShareAmount(contribution));
    await this.miningAccountRepository.save(account);
  }
}
