import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { ShareAmount } from '../../../domain/value-objects/share-amount.vo';

export interface MiningConfigEntity {
  id: string;
  totalShares: ShareAmount;
  distributionPool: ShareAmount;
  remainingDistribution: ShareAmount;
  halvingPeriodYears: number;
  currentEra: number;
  eraStartDate: Date;
  secondDistribution: ShareAmount;
  isActive: boolean;
  activatedAt: Date | null;
  // 全网理论算力
  networkTotalContribution: ShareAmount;
  totalTreeCount: number;
  contributionPerTree: ShareAmount;
  networkLastSyncedAt: Date | null;
}

@Injectable()
export class MiningConfigRepository {
  constructor(private readonly prisma: PrismaService) {}

  async getConfig(): Promise<MiningConfigEntity | null> {
    const record = await this.prisma.miningConfig.findFirst();
    if (!record) {
      return null;
    }
    return this.toDomain(record);
  }

  async saveConfig(config: Partial<MiningConfigEntity>): Promise<void> {
    const existing = await this.prisma.miningConfig.findFirst();

    if (existing) {
      await this.prisma.miningConfig.update({
        where: { id: existing.id },
        data: {
          totalShares: config.totalShares?.value,
          distributionPool: config.distributionPool?.value,
          remainingDistribution: config.remainingDistribution?.value,
          halvingPeriodYears: config.halvingPeriodYears,
          currentEra: config.currentEra,
          eraStartDate: config.eraStartDate,
          secondDistribution: config.secondDistribution?.value,
          isActive: config.isActive,
          activatedAt: config.activatedAt,
        },
      });
    } else {
      await this.prisma.miningConfig.create({
        data: {
          totalShares: config.totalShares?.value || 0,
          distributionPool: config.distributionPool?.value || 0,
          remainingDistribution: config.remainingDistribution?.value || 0,
          halvingPeriodYears: config.halvingPeriodYears || 2,
          currentEra: config.currentEra || 1,
          eraStartDate: config.eraStartDate || new Date(),
          secondDistribution: config.secondDistribution?.value || 0,
          isActive: config.isActive || false,
          activatedAt: config.activatedAt,
        },
      });
    }
  }

  async updateRemainingDistribution(amount: ShareAmount): Promise<void> {
    const existing = await this.prisma.miningConfig.findFirst();
    if (!existing) {
      throw new Error('Mining config not found');
    }

    await this.prisma.miningConfig.update({
      where: { id: existing.id },
      data: { remainingDistribution: amount.value },
    });
  }

  async activate(): Promise<void> {
    const existing = await this.prisma.miningConfig.findFirst();
    if (!existing) {
      throw new Error('Mining config not found');
    }

    await this.prisma.miningConfig.update({
      where: { id: existing.id },
      data: {
        isActive: true,
        activatedAt: new Date(),
        eraStartDate: new Date(),
      },
    });
  }

  async getNetworkTotalContribution(): Promise<ShareAmount> {
    const config = await this.prisma.miningConfig.findFirst();
    if (!config || !config.networkTotalContribution) {
      return ShareAmount.zero();
    }
    return new ShareAmount(config.networkTotalContribution);
  }

  private toDomain(record: any): MiningConfigEntity {
    return {
      id: record.id,
      totalShares: new ShareAmount(record.totalShares),
      distributionPool: new ShareAmount(record.distributionPool),
      remainingDistribution: new ShareAmount(record.remainingDistribution),
      halvingPeriodYears: record.halvingPeriodYears,
      currentEra: record.currentEra,
      eraStartDate: record.eraStartDate,
      secondDistribution: new ShareAmount(record.secondDistribution),
      isActive: record.isActive,
      activatedAt: record.activatedAt,
      networkTotalContribution: new ShareAmount(record.networkTotalContribution || 0),
      totalTreeCount: record.totalTreeCount || 0,
      contributionPerTree: new ShareAmount(record.contributionPerTree || 22617),
      networkLastSyncedAt: record.networkLastSyncedAt,
    };
  }
}
