import { Injectable, Inject, Logger, OnModuleInit } from '@nestjs/common'
import { SystemAccount, SystemAccountLedgerEntryProps } from '@/domain/aggregates'
import {
  SystemAccountType,
  SystemLedgerEntryType,
  SystemAccountStatus,
} from '@/domain/enums'
import {
  ISystemAccountRepository,
  SYSTEM_ACCOUNT_REPOSITORY,
} from '@/domain/repositories'
import { EventPublisherService } from '@/infrastructure/kafka'
import { ApplicationError, NotFoundError } from '@/shared/exceptions'
import Decimal from 'decimal.js'

// 系统账户 DTO
export interface SystemAccountDTO {
  id: string
  accountType: SystemAccountType
  regionCode: string | null
  regionName: string | null
  walletAddress: string | null
  usdtBalance: string
  hashpower: string
  totalReceived: string
  totalTransferred: string
  status: string
  createdAt: Date
  updatedAt: Date
}

// 系统账户流水 DTO
export interface SystemAccountLedgerDTO {
  id: string
  accountId: string
  entryType: SystemLedgerEntryType
  amount: string
  balanceAfter: string
  sourceOrderId: string | null
  txHash: string | null
  memo: string | null
  createdAt: Date
}

// 分配目标接口
export interface AllocationTarget {
  targetType: string
  targetUserId?: string        // 用户账户
  targetSystemAccountId?: bigint   // 系统账户
  amount: Decimal
  hashpowerPercent?: Decimal
}

// 分配请求
export interface ReceiveFundsRequest {
  accountId: bigint
  amount: Decimal
  entryType: SystemLedgerEntryType
  sourceOrderId?: bigint
  sourceRewardId?: bigint
  txHash?: string
  memo?: string
}

@Injectable()
export class SystemAccountApplicationService implements OnModuleInit {
  private readonly logger = new Logger(SystemAccountApplicationService.name)

  constructor(
    @Inject(SYSTEM_ACCOUNT_REPOSITORY)
    private readonly systemAccountRepository: ISystemAccountRepository,
    private readonly eventPublisher: EventPublisherService,
  ) {}

  /**
   * 模块初始化时初始化固定系统账户
   */
  async onModuleInit(): Promise<void> {
    await this.initializeFixedAccounts()
  }

  /**
   * 初始化固定系统账户
   */
  async initializeFixedAccounts(): Promise<void> {
    const fixedAccountTypes = [
      SystemAccountType.COST_ACCOUNT,
      SystemAccountType.OPERATION_ACCOUNT,
      SystemAccountType.HQ_COMMUNITY,
      SystemAccountType.RWAD_POOL_PENDING,
    ]

    for (const accountType of fixedAccountTypes) {
      try {
        await this.systemAccountRepository.getOrCreate(accountType)
        this.logger.log(`初始化系统账户: ${accountType}`)
      } catch (error) {
        this.logger.error(`初始化系统账户失败: ${accountType}`, error)
      }
    }
  }

  /**
   * 获取或创建系统账户（用于按需生成区域账户）
   */
  async getOrCreateSystemAccount(
    accountType: SystemAccountType,
    regionCode?: string,
    regionName?: string,
  ): Promise<SystemAccountDTO> {
    const account = await this.systemAccountRepository.getOrCreate(
      accountType,
      regionCode,
      regionName,
    )
    return this.toDTO(account)
  }

  /**
   * 获取系统账户通过类型
   */
  async getSystemAccountByType(
    accountType: SystemAccountType,
  ): Promise<SystemAccountDTO | null> {
    const account = await this.systemAccountRepository.findByType(accountType)
    return account ? this.toDTO(account) : null
  }

  /**
   * 获取系统账户通过类型和区域
   */
  async getSystemAccountByTypeAndRegion(
    accountType: SystemAccountType,
    regionCode: string,
  ): Promise<SystemAccountDTO | null> {
    const account = await this.systemAccountRepository.findByTypeAndRegion(
      accountType,
      regionCode,
    )
    return account ? this.toDTO(account) : null
  }

  /**
   * 获取所有固定系统账户
   */
  async getAllFixedAccounts(): Promise<SystemAccountDTO[]> {
    const accounts = await this.systemAccountRepository.findAllFixedAccounts()
    return accounts.map((a) => this.toDTO(a))
  }

  /**
   * 确保系统账户有钱包地址（按需生成 MPC 地址）
   */
  async ensureWalletAddress(accountId: bigint): Promise<string> {
    const account = await this.systemAccountRepository.findById(accountId)
    if (!account) {
      throw new NotFoundError('系统账户不存在')
    }

    if (account.walletAddress) {
      return account.walletAddress
    }

    // TODO: 调用 MPC 服务生成地址
    // 此处需要集成 MPC 服务，暂时抛出错误
    throw new ApplicationError('系统账户钱包地址尚未生成，请联系管理员')
  }

  /**
   * 设置系统账户钱包地址（由 MPC 服务调用）
   */
  async setWalletAddress(
    accountId: bigint,
    walletAddress: string,
    mpcPublicKey: string,
  ): Promise<void> {
    const account = await this.systemAccountRepository.findById(accountId)
    if (!account) {
      throw new NotFoundError('系统账户不存在')
    }

    account.setWalletAddress(walletAddress, mpcPublicKey)

    await this.systemAccountRepository.save(account)
    await this.eventPublisher.publishAll(account.domainEvents)
    account.clearDomainEvents()

    this.logger.log(
      `系统账户 ${account.accountType} 设置钱包地址: ${walletAddress}`,
    )
  }

  /**
   * 系统账户接收资金
   */
  async receiveFunds(request: ReceiveFundsRequest): Promise<void> {
    const account = await this.systemAccountRepository.findById(request.accountId)
    if (!account) {
      throw new NotFoundError('系统账户不存在')
    }

    const ledgerEntry = account.receiveFunds({
      amount: request.amount,
      entryType: request.entryType,
      sourceOrderId: request.sourceOrderId,
      sourceRewardId: request.sourceRewardId,
      txHash: request.txHash,
      memo: request.memo,
    })

    // 保存账户和流水
    await this.systemAccountRepository.save(account)
    await this.systemAccountRepository.saveLedgerEntry(ledgerEntry)
    await this.eventPublisher.publishAll(account.domainEvents)
    account.clearDomainEvents()

    this.logger.log(
      `系统账户 ${account.accountType} 收到 ${request.amount.toString()} USDT`,
    )
  }

  /**
   * 批量接收资金（用于认种分配）
   */
  async batchReceiveFunds(requests: ReceiveFundsRequest[]): Promise<void> {
    for (const request of requests) {
      await this.receiveFunds(request)
    }
  }

  /**
   * 系统账户转出资金
   */
  async transferFunds(
    accountId: bigint,
    amount: Decimal,
    txHash?: string,
    memo?: string,
  ): Promise<void> {
    const account = await this.systemAccountRepository.findById(accountId)
    if (!account) {
      throw new NotFoundError('系统账户不存在')
    }

    const ledgerEntry = account.transferFunds({
      amount,
      txHash,
      memo,
    })

    await this.systemAccountRepository.save(account)
    await this.systemAccountRepository.saveLedgerEntry(ledgerEntry)
    await this.eventPublisher.publishAll(account.domainEvents)
    account.clearDomainEvents()

    this.logger.log(
      `系统账户 ${account.accountType} 转出 ${amount.toString()} USDT`,
    )
  }

  /**
   * 查询系统账户流水
   */
  async getAccountLedgerEntries(
    accountId: bigint,
    limit?: number,
    offset?: number,
  ): Promise<SystemAccountLedgerDTO[]> {
    const entries = await this.systemAccountRepository.findLedgerEntriesByAccountId(
      accountId,
      limit,
      offset,
    )

    return entries.map((entry) => this.toLedgerDTO(entry))
  }

  /**
   * 计算认种分配目标（基于授权状态）
   * 这个方法用于 planting-service 调用，确定分配目标
   */
  async calculateAllocationTargets(params: {
    planterId: string
    treeCount: number
    provinceCode: string
    cityCode: string
    referrerId?: string
  }): Promise<AllocationTarget[]> {
    const allocations: AllocationTarget[] = []
    const treeCount = params.treeCount

    // 1. 固定系统账户分配
    const costAccount = await this.systemAccountRepository.findByType(
      SystemAccountType.COST_ACCOUNT,
    )
    const operationAccount = await this.systemAccountRepository.findByType(
      SystemAccountType.OPERATION_ACCOUNT,
    )
    const hqCommunityAccount = await this.systemAccountRepository.findByType(
      SystemAccountType.HQ_COMMUNITY,
    )
    const rwadPoolAccount = await this.systemAccountRepository.findByType(
      SystemAccountType.RWAD_POOL_PENDING,
    )

    if (costAccount) {
      allocations.push({
        targetType: 'COST_ACCOUNT',
        targetSystemAccountId: costAccount.id,
        amount: new Decimal(2800).mul(treeCount),
      })
    }

    if (operationAccount) {
      allocations.push({
        targetType: 'OPERATION_ACCOUNT',
        targetSystemAccountId: operationAccount.id,
        amount: new Decimal(2100).mul(treeCount),
      })
    }

    if (hqCommunityAccount) {
      allocations.push({
        targetType: 'HQ_COMMUNITY',
        targetSystemAccountId: hqCommunityAccount.id,
        amount: new Decimal(203).mul(treeCount),
      })
    }

    if (rwadPoolAccount) {
      allocations.push({
        targetType: 'RWAD_POOL',
        targetSystemAccountId: rwadPoolAccount.id,
        amount: new Decimal(5760).mul(treeCount),
      })
    }

    // 2. 直接推荐人（3600 USDT）
    if (params.referrerId) {
      allocations.push({
        targetType: 'DIRECT_REFERRER',
        targetUserId: params.referrerId,
        amount: new Decimal(3600).mul(treeCount),
      })
    } else if (operationAccount) {
      // 无推荐人，归入运营账户
      allocations.push({
        targetType: 'OPERATION_ACCOUNT',
        targetSystemAccountId: operationAccount.id,
        amount: new Decimal(3600).mul(treeCount),
      })
    }

    // 3. 省公司权益（108 区域 + 144 团队）
    // TODO: 从 authorization-service 查询省公司授权状态
    // 暂时归入系统省账户
    const systemProvince = await this.systemAccountRepository.getOrCreate(
      SystemAccountType.SYSTEM_PROVINCE,
      params.provinceCode,
      params.provinceCode,
    )
    allocations.push({
      targetType: 'PROVINCE_REGION',
      targetSystemAccountId: systemProvince.id,
      amount: new Decimal(108).mul(treeCount),
    })
    allocations.push({
      targetType: 'PROVINCE_TEAM',
      targetSystemAccountId: systemProvince.id,
      amount: new Decimal(144).mul(treeCount),
    })

    // 4. 市公司权益（252 区域 + 288 团队）
    // TODO: 从 authorization-service 查询市公司授权状态
    // 暂时归入系统市账户
    const systemCity = await this.systemAccountRepository.getOrCreate(
      SystemAccountType.SYSTEM_CITY,
      params.cityCode,
      params.cityCode,
    )
    allocations.push({
      targetType: 'CITY_REGION',
      targetSystemAccountId: systemCity.id,
      amount: new Decimal(252).mul(treeCount),
    })
    allocations.push({
      targetType: 'CITY_TEAM',
      targetSystemAccountId: systemCity.id,
      amount: new Decimal(288).mul(treeCount),
    })

    // 5. 社区权益（576 USDT）
    // TODO: 从 authorization-service 查询社区授权状态
    // 暂时归入运营账户
    if (operationAccount) {
      allocations.push({
        targetType: 'COMMUNITY',
        targetSystemAccountId: operationAccount.id,
        amount: new Decimal(576).mul(treeCount),
      })
    }

    return allocations
  }

  // 辅助方法
  private toDTO(account: SystemAccount): SystemAccountDTO {
    return {
      id: account.id.toString(),
      accountType: account.accountType,
      regionCode: account.regionCode,
      regionName: account.regionName,
      walletAddress: account.walletAddress,
      usdtBalance: account.usdtBalance.toString(),
      hashpower: account.hashpower.toString(),
      totalReceived: account.totalReceived.toString(),
      totalTransferred: account.totalTransferred.toString(),
      status: account.status,
      createdAt: account.createdAt,
      updatedAt: account.updatedAt,
    }
  }

  private toLedgerDTO(entry: SystemAccountLedgerEntryProps): SystemAccountLedgerDTO {
    return {
      id: entry.id.toString(),
      accountId: entry.accountId.toString(),
      entryType: entry.entryType,
      amount: entry.amount.toString(),
      balanceAfter: entry.balanceAfter.toString(),
      sourceOrderId: entry.sourceOrderId?.toString() || null,
      txHash: entry.txHash,
      memo: entry.memo,
      createdAt: entry.createdAt,
    }
  }

  // =============== 系统账户报表统计方法 ===============
  // [2026-01-04] 新增：用于 reporting-service 聚合系统账户报表数据
  // 回滚方式：删除以下方法即可

  /**
   * 获取区域系统账户汇总
   * 用于系统账户报表展示省/市区域账户列表和汇总
   */
  async getRegionAccountsSummary(type: 'province' | 'city'): Promise<{
    accounts: SystemAccountDTO[]
    summary: {
      totalBalance: string
      totalReceived: string
      count: number
    }
  }> {
    const accountType = type === 'province'
      ? SystemAccountType.SYSTEM_PROVINCE
      : SystemAccountType.SYSTEM_CITY

    const accounts = await this.systemAccountRepository.findAllRegionAccounts(accountType)

    // 计算汇总
    let totalBalance = new Decimal(0)
    let totalReceived = new Decimal(0)

    const accountDTOs = accounts.map((account) => {
      totalBalance = totalBalance.plus(account.usdtBalance)
      totalReceived = totalReceived.plus(account.totalReceived)
      return this.toDTO(account)
    })

    return {
      accounts: accountDTOs,
      summary: {
        totalBalance: totalBalance.toString(),
        totalReceived: totalReceived.toString(),
        count: accounts.length,
      },
    }
  }

  /**
   * 获取所有系统账户汇总（固定+区域）
   * 用于系统账户报表概览
   */
  async getAllAccountsSummary(): Promise<{
    fixedAccounts: SystemAccountDTO[]
    provinceSummary: {
      totalBalance: string
      totalReceived: string
      count: number
    }
    citySummary: {
      totalBalance: string
      totalReceived: string
      count: number
    }
  }> {
    // 获取固定账户
    const fixedAccounts = await this.getAllFixedAccounts()

    // 获取省区域账户汇总
    const provinceSummary = await this.getRegionAccountsSummary('province')

    // 获取市区域账户汇总
    const citySummary = await this.getRegionAccountsSummary('city')

    return {
      fixedAccounts,
      provinceSummary: provinceSummary.summary,
      citySummary: citySummary.summary,
    }
  }
}
