import { Injectable, Logger } from '@nestjs/common';
import { Decimal } from 'decimal.js';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';

/**
 * 算力系数配置
 */
interface ContributionRateConfig {
  baseContribution: Decimal;      // 基础贡献值 (22617)
  incrementPercentage: Decimal;   // 每单位递增百分比 (0.003 = 0.3%)
  unitSize: number;               // 每单位棵数 (100)
  startTreeNumber: number;        // 开始递增的棵数 (1000)
}

/**
 * 当日算力系数信息
 */
export interface DailyContributionRateInfo {
  effectiveDate: Date;
  contributionPerTree: Decimal;
  multiplier: Decimal;
  unit: number;
  startTreeCount: number;
}

/**
 * 算力系数计算服务
 *
 * 业务规则：
 * - 基础贡献值: 22617 (从第1棵到第999棵)
 * - 从第1000棵开始，每100棵为1个单位
 * - 每个单位递增 0.3% 的贡献值
 * - 同一天认种的用户使用相同的系数（以当日首次认种时的系数为准）
 *
 * 计算公式：
 * - currentUnit = floor((totalTreeCount - startTreeNumber) / unitSize)
 * - currentMultiplier = 1 + (currentUnit * incrementPercentage)
 * - currentContributionPerTree = baseContribution * currentMultiplier
 */
@Injectable()
export class ContributionRateService {
  private readonly logger = new Logger(ContributionRateService.name);

  // 默认配置（可从数据库加载）
  private config: ContributionRateConfig = {
    baseContribution: new Decimal(22617),
    incrementPercentage: new Decimal(0.003),  // 0.3%
    unitSize: 100,
    startTreeNumber: 1000,
  };

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 获取或创建当日算力系数
   *
   * @param adoptionDate 认种日期
   * @returns 当日算力系数信息
   */
  async getOrCreateDailyRate(adoptionDate: Date): Promise<DailyContributionRateInfo> {
    // 标准化日期（去掉时间部分）
    const effectiveDate = this.normalizeDate(adoptionDate);

    // 尝试获取已存在的当日记录
    let dailyRate = await this.prisma.dailyContributionRate.findUnique({
      where: { effectiveDate },
    });

    if (dailyRate) {
      return {
        effectiveDate: dailyRate.effectiveDate,
        contributionPerTree: new Decimal(dailyRate.contributionPerTree.toString()),
        multiplier: new Decimal(dailyRate.startMultiplier.toString()),
        unit: dailyRate.startUnit,
        startTreeCount: dailyRate.startTreeCount,
      };
    }

    // 获取当前全网进度
    const progress = await this.getOrCreateNetworkProgress();

    // 计算当前系数
    const { unit, multiplier, contributionPerTree } = this.calculateRate(progress.totalTreeCount);

    // 创建当日记录
    dailyRate = await this.prisma.dailyContributionRate.create({
      data: {
        effectiveDate,
        startTreeCount: progress.totalTreeCount,
        startUnit: unit,
        startMultiplier: multiplier.toNumber(),
        contributionPerTree: contributionPerTree.toNumber(),
        dailyTreeCount: 0,
        dailyAdoptionOrders: 0,
        dailyAdoptedUsers: 0,
        isClosed: false,
      },
    });

    this.logger.log(
      `Created daily contribution rate for ${effectiveDate.toISOString().split('T')[0]}: ` +
      `unit=${unit}, multiplier=${multiplier.toString()}, contributionPerTree=${contributionPerTree.toString()}`
    );

    return {
      effectiveDate: dailyRate.effectiveDate,
      contributionPerTree,
      multiplier,
      unit,
      startTreeCount: progress.totalTreeCount,
    };
  }

  /**
   * 获取当日每棵树的贡献值
   *
   * @param adoptionDate 认种日期
   * @returns 每棵树的贡献值
   */
  async getContributionPerTree(adoptionDate: Date): Promise<Decimal> {
    const rateInfo = await this.getOrCreateDailyRate(adoptionDate);
    return rateInfo.contributionPerTree;
  }

  /**
   * 更新全网认种进度
   *
   * @param treeCount 新增认种棵数
   * @param adoptionDate 认种日期
   * @param adoptionId 认种ID
   * @param isNewUser 是否为新认种用户
   */
  async updateNetworkProgress(
    treeCount: number,
    adoptionDate: Date,
    adoptionId: bigint,
    isNewUser: boolean,
  ): Promise<void> {
    const effectiveDate = this.normalizeDate(adoptionDate);

    await this.prisma.$transaction(async (tx) => {
      // 更新全网进度
      const progress = await tx.networkAdoptionProgress.findFirst();

      if (!progress) {
        // 首次创建
        const newTotalTreeCount = treeCount;
        const { unit, multiplier, contributionPerTree, nextUnitTreeCount } =
          this.calculateRate(newTotalTreeCount);

        await tx.networkAdoptionProgress.create({
          data: {
            totalTreeCount: newTotalTreeCount,
            totalAdoptionOrders: 1,
            totalAdoptedUsers: isNewUser ? 1 : 0,
            currentUnit: unit,
            currentMultiplier: multiplier.toNumber(),
            currentContributionPerTree: contributionPerTree.toNumber(),
            nextUnitTreeCount,
            lastAdoptionId: adoptionId,
            lastAdoptionDate: effectiveDate,
          },
        });
      } else {
        // 更新现有记录
        const newTotalTreeCount = progress.totalTreeCount + treeCount;
        const { unit, multiplier, contributionPerTree, nextUnitTreeCount } =
          this.calculateRate(newTotalTreeCount);

        await tx.networkAdoptionProgress.update({
          where: { id: progress.id },
          data: {
            totalTreeCount: newTotalTreeCount,
            totalAdoptionOrders: { increment: 1 },
            totalAdoptedUsers: isNewUser ? { increment: 1 } : undefined,
            currentUnit: unit,
            currentMultiplier: multiplier.toNumber(),
            currentContributionPerTree: contributionPerTree.toNumber(),
            nextUnitTreeCount,
            lastAdoptionId: adoptionId,
            lastAdoptionDate: effectiveDate,
          },
        });
      }

      // 更新当日统计
      await tx.dailyContributionRate.upsert({
        where: { effectiveDate },
        create: {
          effectiveDate,
          startTreeCount: 0,
          startUnit: 0,
          startMultiplier: 1.0,
          contributionPerTree: this.config.baseContribution.toNumber(),
          dailyTreeCount: treeCount,
          dailyAdoptionOrders: 1,
          dailyAdoptedUsers: isNewUser ? 1 : 0,
          isClosed: false,
        },
        update: {
          dailyTreeCount: { increment: treeCount },
          dailyAdoptionOrders: { increment: 1 },
          dailyAdoptedUsers: isNewUser ? { increment: 1 } : undefined,
        },
      });
    });

    this.logger.debug(
      `Updated network progress: +${treeCount} trees, adoptionId=${adoptionId}`
    );
  }

  /**
   * 日终结算
   * 关闭当日记录，记录结束状态
   *
   * @param date 要结算的日期
   */
  async closeDailyRate(date: Date): Promise<void> {
    const effectiveDate = this.normalizeDate(date);

    const dailyRate = await this.prisma.dailyContributionRate.findUnique({
      where: { effectiveDate },
    });

    if (!dailyRate) {
      this.logger.warn(`No daily rate found for ${effectiveDate.toISOString().split('T')[0]}`);
      return;
    }

    if (dailyRate.isClosed) {
      this.logger.warn(`Daily rate for ${effectiveDate.toISOString().split('T')[0]} is already closed`);
      return;
    }

    // 获取当前全网进度
    const progress = await this.getOrCreateNetworkProgress();
    const { unit, multiplier } = this.calculateRate(progress.totalTreeCount);

    await this.prisma.dailyContributionRate.update({
      where: { effectiveDate },
      data: {
        endTreeCount: progress.totalTreeCount,
        endUnit: unit,
        endMultiplier: multiplier.toNumber(),
        isClosed: true,
      },
    });

    this.logger.log(
      `Closed daily rate for ${effectiveDate.toISOString().split('T')[0]}: ` +
      `endTreeCount=${progress.totalTreeCount}, endUnit=${unit}, endMultiplier=${multiplier.toString()}`
    );
  }

  /**
   * 获取当前全网进度
   */
  async getNetworkProgress(): Promise<{
    totalTreeCount: number;
    totalAdoptionOrders: number;
    totalAdoptedUsers: number;
    currentUnit: number;
    currentMultiplier: Decimal;
    currentContributionPerTree: Decimal;
    nextUnitTreeCount: number;
  }> {
    const progress = await this.getOrCreateNetworkProgress();
    return {
      totalTreeCount: progress.totalTreeCount,
      totalAdoptionOrders: progress.totalAdoptionOrders,
      totalAdoptedUsers: progress.totalAdoptedUsers,
      currentUnit: progress.currentUnit,
      currentMultiplier: new Decimal(progress.currentMultiplier.toString()),
      currentContributionPerTree: new Decimal(progress.currentContributionPerTree.toString()),
      nextUnitTreeCount: progress.nextUnitTreeCount,
    };
  }

  /**
   * 获取或创建全网进度记录
   */
  private async getOrCreateNetworkProgress() {
    let progress = await this.prisma.networkAdoptionProgress.findFirst();

    if (!progress) {
      progress = await this.prisma.networkAdoptionProgress.create({
        data: {
          totalTreeCount: 0,
          totalAdoptionOrders: 0,
          totalAdoptedUsers: 0,
          currentUnit: 0,
          currentMultiplier: 1.0,
          currentContributionPerTree: this.config.baseContribution.toNumber(),
          nextUnitTreeCount: this.config.startTreeNumber,
        },
      });
    }

    return progress;
  }

  /**
   * 计算算力系数
   *
   * @param totalTreeCount 全网累计认种棵数
   * @returns 单位数、系数、每棵树贡献值、下一单位触发棵数
   */
  private calculateRate(totalTreeCount: number): {
    unit: number;
    multiplier: Decimal;
    contributionPerTree: Decimal;
    nextUnitTreeCount: number;
  } {
    let unit = 0;
    let nextUnitTreeCount = this.config.startTreeNumber;

    // 如果总棵数已经超过起始阈值
    if (totalTreeCount >= this.config.startTreeNumber) {
      // 计算当前单位数
      unit = Math.floor((totalTreeCount - this.config.startTreeNumber) / this.config.unitSize);
      // 计算下一个单位的触发点
      nextUnitTreeCount = this.config.startTreeNumber + ((unit + 1) * this.config.unitSize);
    }

    // 计算系数: 1 + (unit * 0.003)
    const multiplier = new Decimal(1).plus(
      new Decimal(unit).times(this.config.incrementPercentage)
    );

    // 计算每棵树贡献值
    const contributionPerTree = this.config.baseContribution.times(multiplier);

    return {
      unit,
      multiplier,
      contributionPerTree,
      nextUnitTreeCount,
    };
  }

  /**
   * 标准化日期（去掉时间部分）
   */
  private normalizeDate(date: Date): Date {
    const normalized = new Date(date);
    normalized.setHours(0, 0, 0, 0);
    return normalized;
  }

  /**
   * 加载配置（可选，从数据库加载）
   */
  async loadConfig(): Promise<void> {
    const dbConfig = await this.prisma.contributionConfig.findFirst({
      where: { isActive: true },
    });

    if (dbConfig) {
      this.config = {
        baseContribution: new Decimal(dbConfig.baseContribution.toString()),
        incrementPercentage: new Decimal(dbConfig.incrementPercentage.toString()),
        unitSize: dbConfig.unitSize,
        startTreeNumber: dbConfig.startTreeNumber,
      };

      this.logger.log(
        `Loaded contribution rate config: base=${this.config.baseContribution.toString()}, ` +
        `increment=${this.config.incrementPercentage.toString()}, ` +
        `unitSize=${this.config.unitSize}, startTree=${this.config.startTreeNumber}`
      );
    }
  }
}
