import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { TradingAccountAggregate, AssetType } from '../../../domain/aggregates/trading-account.aggregate';
import { Money } from '../../../domain/value-objects/money.vo';

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

  async findByAccountSequence(accountSequence: string): Promise<TradingAccountAggregate | null> {
    const record = await this.prisma.tradingAccount.findUnique({
      where: { accountSequence },
    });
    if (!record) return null;
    return this.toDomain(record);
  }

  async save(aggregate: TradingAccountAggregate): Promise<string> {
    const transactions = aggregate.pendingTransactions;

    const result = await this.prisma.$transaction(async (tx) => {
      const account = await tx.tradingAccount.upsert({
        where: { accountSequence: aggregate.accountSequence },
        create: {
          accountSequence: aggregate.accountSequence,
          shareBalance: aggregate.shareBalance.value,
          cashBalance: aggregate.cashBalance.value,
          frozenShares: aggregate.frozenShares.value,
          frozenCash: aggregate.frozenCash.value,
          totalBought: aggregate.totalBought.value,
          totalSold: aggregate.totalSold.value,
        },
        update: {
          shareBalance: aggregate.shareBalance.value,
          cashBalance: aggregate.cashBalance.value,
          frozenShares: aggregate.frozenShares.value,
          frozenCash: aggregate.frozenCash.value,
          totalBought: aggregate.totalBought.value,
          totalSold: aggregate.totalSold.value,
        },
      });

      if (transactions.length > 0) {
        await tx.tradingTransaction.createMany({
          data: transactions.map((t) => ({
            accountSequence: aggregate.accountSequence,
            type: t.type,
            assetType: t.assetType,
            amount: t.amount.value,
            balanceBefore: t.balanceBefore.value,
            balanceAfter: t.balanceAfter.value,
            referenceId: t.referenceId,
            referenceType: t.referenceType,
            description: t.description,
          })),
        });
      }

      return account.id;
    });

    aggregate.clearPendingTransactions();
    return result;
  }

  async getTransactions(
    accountSequence: string,
    page: number = 1,
    pageSize: number = 50,
  ): Promise<{ data: any[]; total: number }> {
    const [records, total] = await Promise.all([
      this.prisma.tradingTransaction.findMany({
        where: { accountSequence },
        orderBy: { createdAt: 'desc' },
        skip: (page - 1) * pageSize,
        take: pageSize,
      }),
      this.prisma.tradingTransaction.count({ where: { accountSequence } }),
    ]);
    return { data: records, total };
  }

  /**
   * 冻结积分股
   */
  async freezeShares(accountSequence: string, amount: { toNumber: () => number }): Promise<void> {
    await this.prisma.tradingAccount.update({
      where: { accountSequence },
      data: {
        frozenShares: { increment: amount.toNumber() },
      },
    });
  }

  /**
   * 解冻积分股
   */
  async unfreezeShares(accountSequence: string, amount: { toNumber: () => number }): Promise<void> {
    await this.prisma.tradingAccount.update({
      where: { accountSequence },
      data: {
        frozenShares: { decrement: amount.toNumber() },
      },
    });
  }

  /**
   * 冻结积分值（现金）
   */
  async freezeCash(accountSequence: string, amount: { toNumber: () => number }): Promise<void> {
    await this.prisma.tradingAccount.update({
      where: { accountSequence },
      data: {
        frozenCash: { increment: amount.toNumber() },
      },
    });
  }

  /**
   * 解冻积分值（现金）
   */
  async unfreezeCash(accountSequence: string, amount: { toNumber: () => number }): Promise<void> {
    await this.prisma.tradingAccount.update({
      where: { accountSequence },
      data: {
        frozenCash: { decrement: amount.toNumber() },
      },
    });
  }

  /**
   * 更新积分值余额（用于 C2C Bot 扣减卖家余额）
   * @param accountSequence 账户序列号
   * @param delta 变化量（正数增加，负数减少）
   */
  async updateCashBalance(accountSequence: string, delta: string): Promise<void> {
    const deltaNum = parseFloat(delta);
    if (deltaNum > 0) {
      await this.prisma.tradingAccount.update({
        where: { accountSequence },
        data: {
          cashBalance: { increment: deltaNum },
        },
      });
    } else if (deltaNum < 0) {
      await this.prisma.tradingAccount.update({
        where: { accountSequence },
        data: {
          cashBalance: { decrement: Math.abs(deltaNum) },
        },
      });
    }
  }

  private toDomain(record: any): TradingAccountAggregate {
    return TradingAccountAggregate.reconstitute({
      id: record.id,
      accountSequence: record.accountSequence,
      shareBalance: new Money(record.shareBalance),
      cashBalance: new Money(record.cashBalance),
      frozenShares: new Money(record.frozenShares),
      frozenCash: new Money(record.frozenCash),
      totalBought: new Money(record.totalBought),
      totalSold: new Money(record.totalSold),
    });
  }
}
