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<void> {
    const transactions = aggregate.pendingTransactions;

    await this.prisma.$transaction(async (tx) => {
      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,
          })),
        });
      }
    });

    aggregate.clearPendingTransactions();
  }

  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 };
  }

  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),
    });
  }
}
