import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { TradingCalculatorService } from '../../domain/services/trading-calculator.service';
import { TradingAccountRepository } from '../../infrastructure/persistence/repositories/trading-account.repository';
import { BlackHoleRepository } from '../../infrastructure/persistence/repositories/black-hole.repository';
import { CirculationPoolRepository } from '../../infrastructure/persistence/repositories/circulation-pool.repository';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
import { PriceService } from './price.service';
import { Money } from '../../domain/value-objects/money.vo';
import Decimal from 'decimal.js';

// mining-service 返回的账户数据
interface MiningAccountDto {
  accountSequence: string;
  totalMined: string;
  availableBalance: string;
  frozenBalance: string;
  totalBalance: string;
  totalContribution: string;
  lastSyncedAt: string | null;
}

export interface AssetDisplay {
  // 挖矿账户积分股余额
  miningShareBalance: string;
  // 交易账户积分股余额
  tradingShareBalance: string;
  // 总积分股余额（挖矿 + 交易）
  shareBalance: string;
  // 账户现金余额（交易账户）
  cashBalance: string;
  // 冻结积分股（挖矿冻结 + 交易冻结）
  frozenShares: string;
  // 冻结现金
  frozenCash: string;
  // 可用积分股（挖矿可用 + 交易可用）
  availableShares: string;
  // 可用现金
  availableCash: string;
  // 当前价格
  currentPrice: string;
  // 销毁倍数
  burnMultiplier: string;
  // 有效积分股（含销毁加成）
  effectiveShares: string;
  // 资产显示值 = (账户积分股 + 账户积分股 × 倍数) × 积分股价
  displayAssetValue: string;
  // 每秒增长量（需要外部传入每日分配量）
  assetGrowthPerSecond: string;
  // 累计买入
  totalBought: string;
  // 累计卖出
  totalSold: string;
}

@Injectable()
export class AssetService {
  private readonly logger = new Logger(AssetService.name);
  private readonly calculator = new TradingCalculatorService();
  private readonly miningServiceUrl: string;

  // 缓存做市商 accountSequence
  private mmAccountSequence: string | null = null;

  constructor(
    private readonly tradingAccountRepository: TradingAccountRepository,
    private readonly blackHoleRepository: BlackHoleRepository,
    private readonly circulationPoolRepository: CirculationPoolRepository,
    private readonly prisma: PrismaService,
    private readonly priceService: PriceService,
    private readonly configService: ConfigService,
  ) {
    this.miningServiceUrl = this.configService.get<string>(
      'MINING_SERVICE_URL',
      'http://localhost:3021',
    );
  }

  /**
   * 获取用户资产显示（汇总挖矿账户 + 交易账户）
   * 资产显示 = (总积分股 + 总积分股 × 倍数) × 积分股价
   *
   * @param accountSequence 账户序号
   * @param dailyAllocation 用户每天分配的积分股（可选，用于计算每秒增长）
   */
  async getAssetDisplay(
    accountSequence: string,
    dailyAllocation?: string,
  ): Promise<AssetDisplay | null> {
    // 并行获取交易账户和挖矿账户数据
    const [tradingAccount, miningAccount] = await Promise.all([
      this.tradingAccountRepository.findByAccountSequence(accountSequence),
      this.getMiningAccountBalance(accountSequence),
    ]);

    // 如果两个账户都不存在，返回 null
    if (!tradingAccount && !miningAccount) {
      return null;
    }

    // 获取当前价格信息
    const priceInfo = await this.priceService.getCurrentPrice();
    const price = new Money(priceInfo.price);
    const burnMultiplier = new Decimal(priceInfo.burnMultiplier);

    // 挖矿账户余额
    const miningShareBalance = new Money(miningAccount?.availableBalance || '0');
    const miningFrozenShares = new Money(miningAccount?.frozenBalance || '0');

    // 交易账户余额
    const tradingShareBalance = tradingAccount?.shareBalance || Money.zero();
    const tradingFrozenShares = tradingAccount?.frozenShares || Money.zero();
    const cashBalance = tradingAccount?.cashBalance || Money.zero();
    const frozenCash = tradingAccount?.frozenCash || Money.zero();
    const totalBought = tradingAccount?.totalBought || Money.zero();
    const totalSold = tradingAccount?.totalSold || Money.zero();

    // 汇总余额
    const totalShareBalance = miningShareBalance.add(tradingShareBalance);
    const totalFrozenShares = miningFrozenShares.add(tradingFrozenShares);
    const totalAvailableShares = miningShareBalance.add(
      tradingAccount?.availableShares || Money.zero(),
    );

    // 计算有效积分股 = 总余额 × (1 + 倍数)
    const multiplierFactor = new Decimal(1).plus(burnMultiplier);
    const effectiveShares = totalShareBalance.value.times(multiplierFactor);

    // 计算资产显示值（使用汇总后的余额）
    const displayAssetValue = this.calculator.calculateDisplayAssetValue(
      totalShareBalance,
      burnMultiplier,
      price,
    );

    // 计算每秒增长量
    let assetGrowthPerSecond = Money.zero();
    if (dailyAllocation) {
      const dailyAmount = new Money(dailyAllocation);
      assetGrowthPerSecond = this.calculator.calculateAssetGrowthPerSecond(dailyAmount);
    }

    return {
      miningShareBalance: miningShareBalance.toFixed(8),
      tradingShareBalance: tradingShareBalance.toFixed(8),
      shareBalance: totalShareBalance.toFixed(8),
      cashBalance: cashBalance.toFixed(8),
      frozenShares: totalFrozenShares.toFixed(8),
      frozenCash: frozenCash.toFixed(8),
      availableShares: totalAvailableShares.toFixed(8),
      availableCash: (tradingAccount?.availableCash || Money.zero()).toFixed(8),
      currentPrice: price.toFixed(18),
      burnMultiplier: burnMultiplier.toFixed(18),
      effectiveShares: new Money(effectiveShares).toFixed(8),
      displayAssetValue: displayAssetValue.toFixed(8),
      assetGrowthPerSecond: assetGrowthPerSecond.toFixed(18),
      totalBought: totalBought.toFixed(8),
      totalSold: totalSold.toFixed(8),
    };
  }

  /**
   * 调用 mining-service 获取挖矿账户余额
   */
  private async getMiningAccountBalance(
    accountSequence: string,
  ): Promise<MiningAccountDto | null> {
    try {
      const response = await fetch(
        `${this.miningServiceUrl}/api/v2/mining/accounts/${accountSequence}`,
      );

      if (!response.ok) {
        return null;
      }

      const result = await response.json();
      if (!result.success || !result.data) {
        return null;
      }

      return result.data as MiningAccountDto;
    } catch (error) {
      this.logger.warn(`Failed to fetch mining account ${accountSequence}: ${error}`);
      return null;
    }
  }

  /**
   * 计算资产每秒增长量
   * 资产每秒增长量 = 用户每天分配的积分股 ÷ 24 ÷ 60 ÷ 60
   */
  calculateAssetGrowthPerSecond(dailyAllocation: string): string {
    const dailyAmount = new Money(dailyAllocation);
    const perSecond = this.calculator.calculateAssetGrowthPerSecond(dailyAmount);
    return perSecond.toFixed(18);
  }

  /**
   * 预估卖出收益
   * 卖出交易额 = (卖出量 + 卖出销毁量) × 积分股价
   */
  async estimateSellProceeds(sellQuantity: string): Promise<{
    sellQuantity: string;
    burnQuantity: string;
    effectiveQuantity: string;
    price: string;
    proceeds: string;
    burnMultiplier: string;
  }> {
    const quantity = new Money(sellQuantity);
    const result = await this.priceService.calculateSellAmount(quantity);

    return {
      sellQuantity: quantity.toFixed(8),
      burnQuantity: result.burnQuantity.toFixed(8),
      effectiveQuantity: result.effectiveQuantity.toFixed(8),
      price: result.price.toFixed(18),
      proceeds: result.amount.toFixed(8),
      burnMultiplier: (await this.priceService.getCurrentBurnMultiplier()).toFixed(18),
    };
  }

  /**
   * 从 mining-service 获取全网已挖矿产出的积分股总量
   *
   * 调用 mining-service 的 GET /mining/progress 接口，返回 totalDistributed
   * （用户已挖 + 系统已挖的总和）。
   *
   * 该值用于前端"流通池"展示，表示已经通过挖矿产出并进入流通的积分股数量。
   * 注意：此值不参与价格公式计算，价格公式使用的是交易流通池（circulationPool）。
   */
  private async getTotalMinedFromMiningService(): Promise<Money> {
    try {
      const response = await fetch(
        `${this.miningServiceUrl}/api/v2/mining/progress`,
      );

      if (!response.ok) {
        this.logger.warn(`Failed to fetch mining progress: HTTP ${response.status}`);
        return Money.zero();
      }

      const result = await response.json();
      // totalDistributed = 用户已挖总量 + 系统已挖总量
      // mining-service 返回格式: { success: true, data: { totalDistributed: "..." } }
      const totalDistributed = result?.data?.totalDistributed || result?.totalDistributed;
      if (totalDistributed) {
        return new Money(totalDistributed);
      }
      return Money.zero();
    } catch (error) {
      this.logger.warn(`Failed to fetch total mined from mining-service: ${error}`);
      return Money.zero();
    }
  }

  /**
   * 获取做市商积分值余额（即价格公式中的"绿积分"）
   */
  private async getGreenPoints(): Promise<Money> {
    if (!this.mmAccountSequence) {
      const config = await this.prisma.marketMakerConfig.findUnique({
        where: { name: 'MAIN_MARKET_MAKER' },
      });
      this.mmAccountSequence = config?.accountSequence || null;
    }
    if (!this.mmAccountSequence) return Money.zero();

    const account = await this.prisma.tradingAccount.findUnique({
      where: { accountSequence: this.mmAccountSequence },
    });
    return account ? new Money(account.cashBalance) : Money.zero();
  }

  /**
   * 获取市场概览
   *
   * 返回字段说明：
   * - circulationPool: 价格公式中的流通池（卖出交易产生的积分股），用于价格/倍数计算
   * - totalMined: 全网已挖矿产出的积分股总量（用户+系统），前端"已分配积分股"展示此值
   * - totalSellBurned: 全网卖出交易产生的销毁总量（burn_records中SELL_BURN的sum），前端"全网兑换销毁量"展示此值
   */
  async getMarketOverview(): Promise<{
    price: string;
    greenPoints: string;
    blackHoleAmount: string;
    circulationPool: string;
    totalMined: string;
    totalSellBurned: string;
    effectiveDenominator: string;
    burnMultiplier: string;
    totalShares: string;
    burnTarget: string;
    burnProgress: string;
  }> {
    const [greenPoints, blackHole, circulationPool, totalMined, totalSellBurned] = await Promise.all([
      this.getGreenPoints(),
      this.blackHoleRepository.getBlackHole(),
      this.circulationPoolRepository.getPool(),
      this.getTotalMinedFromMiningService(),
      this.blackHoleRepository.getTotalSellBurned(),
    ]);
    const blackHoleAmount = blackHole?.totalBurned || Money.zero();
    const circulationPoolAmount = circulationPool?.totalShares || Money.zero();

    // 计算价格（使用交易流通池，非已挖总量）
    const price = this.calculator.calculatePrice(greenPoints, blackHoleAmount, circulationPoolAmount);

    // 计算有效分母
    const effectiveDenominator = this.calculator.calculateEffectiveDenominator(
      blackHoleAmount,
      circulationPoolAmount,
    );

    // 计算销毁倍数
    const burnMultiplier = this.calculator.calculateSellBurnMultiplier(
      blackHoleAmount,
      circulationPoolAmount,
    );

    // 销毁进度
    const targetBurn = blackHole?.targetBurn || new Money(TradingCalculatorService.BURN_TARGET);
    const burnProgress = blackHoleAmount.value.dividedBy(targetBurn.value).times(100);

    return {
      price: price.toFixed(18),
      greenPoints: greenPoints.toFixed(8),
      blackHoleAmount: blackHoleAmount.toFixed(8),
      circulationPool: circulationPoolAmount.toFixed(8),
      totalMined: totalMined.toFixed(8),
      totalSellBurned: totalSellBurned.toFixed(8),
      effectiveDenominator: effectiveDenominator.toFixed(8),
      burnMultiplier: burnMultiplier.toFixed(18),
      totalShares: TradingCalculatorService.TOTAL_SHARES.toFixed(8),
      burnTarget: targetBurn.toFixed(8),
      burnProgress: burnProgress.toFixed(4),
    };
  }
}
