import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { Money } from '../../../domain/value-objects/money.vo';
import Decimal from 'decimal.js';

export interface BlackHoleEntity {
  id: string;
  totalBurned: Money;
  targetBurn: Money;
  remainingBurn: Money;
  lastBurnMinute: Date | null;
}

export interface BurnRecordEntity {
  id: string;
  blackHoleId: string;
  burnMinute: Date;
  burnAmount: Money;
  remainingTarget: Money;
  sourceType: string | null;
  sourceAccountSeq: string | null;
  sourceOrderNo: string | null;
  memo: string | null;
  createdAt: Date;
}

export type BurnSourceType = 'MINUTE_BURN' | 'SELL_BURN';

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

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

  async initializeBlackHole(targetBurn: Money): Promise<BlackHoleEntity> {
    const existing = await this.prisma.blackHole.findFirst();
    if (existing) {
      return this.toDomain(existing);
    }

    const record = await this.prisma.blackHole.create({
      data: {
        totalBurned: 0,
        targetBurn: targetBurn.value,
        remainingBurn: targetBurn.value,
      },
    });

    return this.toDomain(record);
  }

  /**
   * 记录销毁（每分钟自动销毁）
   */
  async recordMinuteBurn(burnMinute: Date, burnAmount: Money): Promise<BurnRecordEntity> {
    return this.recordBurn(burnMinute, burnAmount, 'MINUTE_BURN');
  }

  /**
   * 记录销毁（卖出销毁）
   */
  async recordSellBurn(
    burnMinute: Date,
    burnAmount: Money,
    accountSeq: string,
    orderNo: string,
  ): Promise<BurnRecordEntity> {
    return this.recordBurn(burnMinute, burnAmount, 'SELL_BURN', accountSeq, orderNo);
  }

  /**
   * 记录销毁通用方法
   */
  private async recordBurn(
    burnMinute: Date,
    burnAmount: Money,
    sourceType: BurnSourceType,
    sourceAccountSeq?: string,
    sourceOrderNo?: string,
  ): Promise<BurnRecordEntity> {
    const blackHole = await this.prisma.blackHole.findFirst();
    if (!blackHole) {
      throw new Error('Black hole not initialized');
    }

    const newTotalBurned = new Decimal(blackHole.totalBurned.toString()).plus(burnAmount.value);
    const newRemainingBurn = new Decimal(blackHole.targetBurn.toString()).minus(newTotalBurned);

    const memo =
      sourceType === 'MINUTE_BURN'
        ? `每分钟自动销毁 ${burnAmount.toFixed(8)}`
        : `卖出销毁, 账户[${sourceAccountSeq}], 订单[${sourceOrderNo}], 数量${burnAmount.toFixed(8)}`;

    const [, burnRecord] = await this.prisma.$transaction([
      this.prisma.blackHole.update({
        where: { id: blackHole.id },
        data: {
          totalBurned: newTotalBurned,
          remainingBurn: newRemainingBurn.isNegative() ? 0 : newRemainingBurn,
          lastBurnMinute: burnMinute,
        },
      }),
      this.prisma.burnRecord.create({
        data: {
          blackHoleId: blackHole.id,
          burnMinute,
          burnAmount: burnAmount.value,
          remainingTarget: newRemainingBurn.isNegative() ? 0 : newRemainingBurn,
          sourceType,
          sourceAccountSeq,
          sourceOrderNo,
          memo,
        },
      }),
    ]);

    return this.toBurnRecordDomain(burnRecord);
  }

  async getBurnRecords(
    page: number,
    pageSize: number,
    sourceType?: BurnSourceType,
  ): Promise<{
    data: BurnRecordEntity[];
    total: number;
  }> {
    const where = sourceType ? { sourceType } : {};

    const [records, total] = await Promise.all([
      this.prisma.burnRecord.findMany({
        where,
        orderBy: { burnMinute: 'desc' },
        skip: (page - 1) * pageSize,
        take: pageSize,
      }),
      this.prisma.burnRecord.count({ where }),
    ]);

    return {
      data: records.map((r) => this.toBurnRecordDomain(r)),
      total,
    };
  }

  /**
   * 获取全网卖出销毁总量
   */
  async getTotalSellBurned(): Promise<Money> {
    const result = await this.prisma.burnRecord.aggregate({
      where: { sourceType: 'SELL_BURN' },
      _sum: { burnAmount: true },
    });
    return new Money(result._sum.burnAmount || 0);
  }

  async getTodayBurnAmount(): Promise<Money> {
    const today = new Date();
    today.setHours(0, 0, 0, 0);

    const result = await this.prisma.burnRecord.aggregate({
      where: {
        burnMinute: { gte: today },
      },
      _sum: { burnAmount: true },
    });

    return new Money(result._sum.burnAmount || 0);
  }

  private toDomain(record: any): BlackHoleEntity {
    return {
      id: record.id,
      totalBurned: new Money(record.totalBurned),
      targetBurn: new Money(record.targetBurn),
      remainingBurn: new Money(record.remainingBurn),
      lastBurnMinute: record.lastBurnMinute,
    };
  }

  private toBurnRecordDomain(record: any): BurnRecordEntity {
    return {
      id: record.id,
      blackHoleId: record.blackHoleId,
      burnMinute: record.burnMinute,
      burnAmount: new Money(record.burnAmount),
      remainingTarget: new Money(record.remainingTarget),
      sourceType: record.sourceType,
      sourceAccountSeq: record.sourceAccountSeq,
      sourceOrderNo: record.sourceOrderNo,
      memo: record.memo,
      createdAt: record.createdAt,
    };
  }
}
