import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
  PoolAccount,
  PoolAccountTransaction,
  PoolAccountType,
  TransactionType,
  CounterpartyType,
  Prisma,
} from '@prisma/client';
import Decimal from 'decimal.js';

export interface CreatePoolAccountInput {
  poolType: PoolAccountType;
  name: string;
  targetBurn?: Decimal;
  description?: string;
}

export interface PoolTransactionInput {
  poolAccountId: string;
  poolType: PoolAccountType;
  transactionType: TransactionType;
  amount: Decimal;
  balanceBefore: Decimal;
  balanceAfter: Decimal;
  counterpartyType?: CounterpartyType;
  counterpartyAccountSeq?: string;
  counterpartyUserId?: string;
  counterpartySystemId?: string;
  counterpartyPoolType?: PoolAccountType;
  counterpartyAddress?: string;
  referenceId?: string;
  referenceType?: string;
  txHash?: string;
  memo?: string;
  metadata?: any;
}

@Injectable()
export class PoolAccountRepository {
  private readonly logger = new Logger(PoolAccountRepository.name);

  constructor(private readonly prisma: PrismaService) {}

  async create(input: CreatePoolAccountInput): Promise<PoolAccount> {
    return this.prisma.poolAccount.create({
      data: {
        poolType: input.poolType,
        name: input.name,
        targetBurn: input.targetBurn?.toFixed(8),
        remainingBurn: input.targetBurn?.toFixed(8),
        description: input.description,
      },
    });
  }

  async findByType(poolType: PoolAccountType): Promise<PoolAccount | null> {
    return this.prisma.poolAccount.findUnique({
      where: { poolType },
    });
  }

  async findById(id: string): Promise<PoolAccount | null> {
    return this.prisma.poolAccount.findUnique({
      where: { id },
    });
  }

  async findAll(): Promise<PoolAccount[]> {
    return this.prisma.poolAccount.findMany({
      orderBy: { createdAt: 'asc' },
    });
  }

  /**
   * 更新池余额并记录交易（原子操作）
   */
  async updateBalanceWithTransaction(
    poolType: PoolAccountType,
    amount: Decimal,
    transactionInput: Omit<PoolTransactionInput, 'poolAccountId' | 'poolType' | 'amount' | 'balanceBefore' | 'balanceAfter'>,
  ): Promise<{ pool: PoolAccount; transaction: PoolAccountTransaction }> {
    return this.prisma.$transaction(async (tx) => {
      const pool = await tx.poolAccount.findUnique({
        where: { poolType },
      });

      if (!pool) {
        throw new Error(`Pool account not found: ${poolType}`);
      }

      const currentBalance = new Decimal(pool.balance.toString());
      const newBalance = currentBalance.plus(amount);

      if (newBalance.lessThan(0)) {
        throw new Error(`Insufficient pool balance: ${currentBalance} + ${amount} < 0`);
      }

      // 更新池余额
      const updatedPool = await tx.poolAccount.update({
        where: { poolType },
        data: {
          balance: newBalance.toFixed(8),
          totalInflow: amount.greaterThan(0)
            ? new Decimal(pool.totalInflow.toString()).plus(amount).toFixed(8)
            : pool.totalInflow,
          totalOutflow: amount.lessThan(0)
            ? new Decimal(pool.totalOutflow.toString()).plus(amount.abs()).toFixed(8)
            : pool.totalOutflow,
        },
      });

      // 记录交易
      const transaction = await tx.poolAccountTransaction.create({
        data: {
          poolAccountId: pool.id,
          poolType,
          transactionType: transactionInput.transactionType,
          amount: amount.toFixed(8),
          balanceBefore: currentBalance.toFixed(8),
          balanceAfter: newBalance.toFixed(8),
          counterpartyType: transactionInput.counterpartyType,
          counterpartyAccountSeq: transactionInput.counterpartyAccountSeq,
          counterpartyUserId: transactionInput.counterpartyUserId,
          counterpartySystemId: transactionInput.counterpartySystemId,
          counterpartyPoolType: transactionInput.counterpartyPoolType,
          counterpartyAddress: transactionInput.counterpartyAddress,
          referenceId: transactionInput.referenceId,
          referenceType: transactionInput.referenceType,
          txHash: transactionInput.txHash,
          memo: transactionInput.memo,
          metadata: transactionInput.metadata,
        },
      });

      return { pool: updatedPool, transaction };
    });
  }

  /**
   * 销毁到黑洞池（特殊操作）
   */
  async burnToBlackHole(
    fromPoolType: PoolAccountType,
    amount: Decimal,
    sourceInfo: {
      counterpartyType?: CounterpartyType;
      counterpartyAccountSeq?: string;
      counterpartyUserId?: string;
      memo?: string;
    },
  ): Promise<{
    fromPool: PoolAccount;
    blackHolePool: PoolAccount;
    fromTransaction: PoolAccountTransaction;
    blackHoleTransaction: PoolAccountTransaction;
  }> {
    return this.prisma.$transaction(async (tx) => {
      // 从源池扣除
      const fromPool = await tx.poolAccount.findUnique({
        where: { poolType: fromPoolType },
      });

      if (!fromPool) {
        throw new Error(`Source pool not found: ${fromPoolType}`);
      }

      const fromBalance = new Decimal(fromPool.balance.toString());
      if (fromBalance.lessThan(amount)) {
        throw new Error(`Insufficient balance in ${fromPoolType}: ${fromBalance} < ${amount}`);
      }

      const newFromBalance = fromBalance.minus(amount);

      const updatedFromPool = await tx.poolAccount.update({
        where: { poolType: fromPoolType },
        data: {
          balance: newFromBalance.toFixed(8),
          totalOutflow: new Decimal(fromPool.totalOutflow.toString()).plus(amount).toFixed(8),
        },
      });

      // 黑洞池增加
      const blackHolePool = await tx.poolAccount.findUnique({
        where: { poolType: 'BLACK_HOLE_POOL' },
      });

      if (!blackHolePool) {
        throw new Error('Black hole pool not found');
      }

      const blackHoleBalance = new Decimal(blackHolePool.balance.toString());
      const newBlackHoleBalance = blackHoleBalance.plus(amount);
      const newRemainingBurn = blackHolePool.remainingBurn
        ? new Decimal(blackHolePool.remainingBurn.toString()).minus(amount)
        : null;

      const updatedBlackHolePool = await tx.poolAccount.update({
        where: { poolType: 'BLACK_HOLE_POOL' },
        data: {
          balance: newBlackHoleBalance.toFixed(8),
          totalInflow: new Decimal(blackHolePool.totalInflow.toString()).plus(amount).toFixed(8),
          remainingBurn: newRemainingBurn?.toFixed(8),
        },
      });

      // 记录源池交易
      const fromTransaction = await tx.poolAccountTransaction.create({
        data: {
          poolAccountId: fromPool.id,
          poolType: fromPoolType,
          transactionType: 'BURN',
          amount: amount.negated().toFixed(8),
          balanceBefore: fromBalance.toFixed(8),
          balanceAfter: newFromBalance.toFixed(8),
          counterpartyType: 'POOL',
          counterpartyPoolType: 'BLACK_HOLE_POOL',
          counterpartyAccountSeq: sourceInfo.counterpartyAccountSeq,
          counterpartyUserId: sourceInfo.counterpartyUserId,
          memo: sourceInfo.memo || `销毁到黑洞池, 数量${amount.toFixed(8)}`,
        },
      });

      // 记录黑洞池交易
      const blackHoleTransaction = await tx.poolAccountTransaction.create({
        data: {
          poolAccountId: blackHolePool.id,
          poolType: 'BLACK_HOLE_POOL',
          transactionType: 'BURN',
          amount: amount.toFixed(8),
          balanceBefore: blackHoleBalance.toFixed(8),
          balanceAfter: newBlackHoleBalance.toFixed(8),
          counterpartyType: sourceInfo.counterpartyType || 'POOL',
          counterpartyPoolType: fromPoolType,
          counterpartyAccountSeq: sourceInfo.counterpartyAccountSeq,
          counterpartyUserId: sourceInfo.counterpartyUserId,
          memo: sourceInfo.memo || `从${fromPoolType}接收销毁, 数量${amount.toFixed(8)}`,
        },
      });

      return {
        fromPool: updatedFromPool,
        blackHolePool: updatedBlackHolePool,
        fromTransaction,
        blackHoleTransaction,
      };
    });
  }

  async getTransactions(
    poolType: PoolAccountType,
    options?: {
      transactionType?: TransactionType;
      startDate?: Date;
      endDate?: Date;
      limit?: number;
      offset?: number;
    },
  ): Promise<{ transactions: PoolAccountTransaction[]; total: number }> {
    const where: Prisma.PoolAccountTransactionWhereInput = {
      poolType,
    };

    if (options?.transactionType) {
      where.transactionType = options.transactionType;
    }
    if (options?.startDate || options?.endDate) {
      where.createdAt = {};
      if (options.startDate) where.createdAt.gte = options.startDate;
      if (options.endDate) where.createdAt.lte = options.endDate;
    }

    const [transactions, total] = await Promise.all([
      this.prisma.poolAccountTransaction.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        take: options?.limit || 50,
        skip: options?.offset || 0,
      }),
      this.prisma.poolAccountTransaction.count({ where }),
    ]);

    return { transactions, total };
  }

  /**
   * 获取所有池的统计信息
   */
  async getPoolStats(): Promise<{
    poolType: PoolAccountType;
    balance: string;
    totalInflow: string;
    totalOutflow: string;
    targetBurn?: string;
    remainingBurn?: string;
  }[]> {
    const pools = await this.prisma.poolAccount.findMany({
      select: {
        poolType: true,
        balance: true,
        totalInflow: true,
        totalOutflow: true,
        targetBurn: true,
        remainingBurn: true,
      },
    });

    return pools.map((p) => ({
      poolType: p.poolType,
      balance: p.balance.toString(),
      totalInflow: p.totalInflow.toString(),
      totalOutflow: p.totalOutflow.toString(),
      targetBurn: p.targetBurn?.toString(),
      remainingBurn: p.remainingBurn?.toString(),
    }));
  }
}
