import { AggregateRoot } from './aggregate-root.base'
import { SystemAccountType, SystemLedgerEntryType, SystemAccountStatus } from '@/domain/enums'
import { DomainError } from '@/shared/exceptions'
import {
  SystemAccountCreatedEvent,
  SystemAccountWalletGeneratedEvent,
  SystemAccountFundsReceivedEvent,
  SystemAccountFundsTransferredEvent,
} from '@/domain/events'
import Decimal from 'decimal.js'

export interface SystemAccountProps {
  id: bigint
  accountType: SystemAccountType
  regionCode: string | null
  regionName: string | null
  walletAddress: string | null
  mpcPublicKey: string | null
  usdtBalance: Decimal
  hashpower: Decimal
  totalReceived: Decimal
  totalTransferred: Decimal
  status: SystemAccountStatus
  createdAt: Date
  updatedAt: Date
}

export interface SystemAccountLedgerEntryProps {
  id: bigint
  accountId: bigint
  entryType: SystemLedgerEntryType
  amount: Decimal
  balanceAfter: Decimal
  sourceOrderId: bigint | null
  sourceRewardId: bigint | null
  txHash: string | null
  memo: string | null
  createdAt: Date
}

export class SystemAccount extends AggregateRoot {
  private _id: bigint
  private _accountType: SystemAccountType
  private _regionCode: string | null
  private _regionName: string | null
  private _walletAddress: string | null
  private _mpcPublicKey: string | null
  private _usdtBalance: Decimal
  private _hashpower: Decimal
  private _totalReceived: Decimal
  private _totalTransferred: Decimal
  private _status: SystemAccountStatus
  private _createdAt: Date
  private _updatedAt: Date

  // Getters
  get id(): bigint {
    return this._id
  }
  get accountType(): SystemAccountType {
    return this._accountType
  }
  get regionCode(): string | null {
    return this._regionCode
  }
  get regionName(): string | null {
    return this._regionName
  }
  get walletAddress(): string | null {
    return this._walletAddress
  }
  get mpcPublicKey(): string | null {
    return this._mpcPublicKey
  }
  get usdtBalance(): Decimal {
    return this._usdtBalance
  }
  get hashpower(): Decimal {
    return this._hashpower
  }
  get totalReceived(): Decimal {
    return this._totalReceived
  }
  get totalTransferred(): Decimal {
    return this._totalTransferred
  }
  get status(): SystemAccountStatus {
    return this._status
  }
  get createdAt(): Date {
    return this._createdAt
  }
  get updatedAt(): Date {
    return this._updatedAt
  }
  get isActive(): boolean {
    return this._status === SystemAccountStatus.ACTIVE
  }
  get hasWallet(): boolean {
    return this._walletAddress !== null
  }

  // 私有构造函数
  private constructor(props: SystemAccountProps) {
    super()
    this._id = props.id
    this._accountType = props.accountType
    this._regionCode = props.regionCode
    this._regionName = props.regionName
    this._walletAddress = props.walletAddress
    this._mpcPublicKey = props.mpcPublicKey
    this._usdtBalance = props.usdtBalance
    this._hashpower = props.hashpower
    this._totalReceived = props.totalReceived
    this._totalTransferred = props.totalTransferred
    this._status = props.status
    this._createdAt = props.createdAt
    this._updatedAt = props.updatedAt
  }

  // 工厂方法 - 从数据库重建
  static fromPersistence(props: SystemAccountProps): SystemAccount {
    return new SystemAccount(props)
  }

  // 工厂方法 - 创建固定系统账户（成本、运营、总部社区、矿池）
  static createFixedAccount(accountType: SystemAccountType): SystemAccount {
    if (
      accountType === SystemAccountType.SYSTEM_PROVINCE ||
      accountType === SystemAccountType.SYSTEM_CITY
    ) {
      throw new DomainError('区域系统账户需要指定区域信息')
    }

    const account = new SystemAccount({
      id: BigInt(0), // 由数据库生成
      accountType,
      regionCode: null,
      regionName: null,
      walletAddress: null,
      mpcPublicKey: null,
      usdtBalance: new Decimal(0),
      hashpower: new Decimal(0),
      totalReceived: new Decimal(0),
      totalTransferred: new Decimal(0),
      status: SystemAccountStatus.ACTIVE,
      createdAt: new Date(),
      updatedAt: new Date(),
    })

    account.addDomainEvent(
      new SystemAccountCreatedEvent({
        accountType,
        regionCode: null,
      }),
    )

    return account
  }

  // 工厂方法 - 创建区域系统账户（省/市）
  static createRegionAccount(params: {
    accountType: SystemAccountType.SYSTEM_PROVINCE | SystemAccountType.SYSTEM_CITY
    regionCode: string
    regionName: string
  }): SystemAccount {
    const account = new SystemAccount({
      id: BigInt(0), // 由数据库生成
      accountType: params.accountType,
      regionCode: params.regionCode,
      regionName: params.regionName,
      walletAddress: null,
      mpcPublicKey: null,
      usdtBalance: new Decimal(0),
      hashpower: new Decimal(0),
      totalReceived: new Decimal(0),
      totalTransferred: new Decimal(0),
      status: SystemAccountStatus.ACTIVE,
      createdAt: new Date(),
      updatedAt: new Date(),
    })

    account.addDomainEvent(
      new SystemAccountCreatedEvent({
        accountType: params.accountType,
        regionCode: params.regionCode,
      }),
    )

    return account
  }

  // 核心领域行为

  /**
   * 设置 MPC 生成的钱包地址
   */
  setWalletAddress(walletAddress: string, mpcPublicKey: string): void {
    if (this._walletAddress) {
      throw new DomainError('钱包地址已设置，不能重复设置')
    }

    this._walletAddress = walletAddress
    this._mpcPublicKey = mpcPublicKey
    this._updatedAt = new Date()

    this.addDomainEvent(
      new SystemAccountWalletGeneratedEvent({
        accountId: this._id.toString(),
        accountType: this._accountType,
        walletAddress,
        mpcPublicKey,
      }),
    )
  }

  /**
   * 接收资金（从认种分配或过期奖励）
   */
  receiveFunds(params: {
    amount: Decimal
    entryType: SystemLedgerEntryType
    sourceOrderId?: bigint
    sourceRewardId?: bigint
    txHash?: string
    memo?: string
  }): SystemAccountLedgerEntryProps {
    if (!this.isActive) {
      throw new DomainError('系统账户已停用')
    }

    if (params.amount.lte(0)) {
      throw new DomainError('金额必须大于0')
    }

    const newBalance = this._usdtBalance.plus(params.amount)
    this._usdtBalance = newBalance
    this._totalReceived = this._totalReceived.plus(params.amount)
    this._updatedAt = new Date()

    const ledgerEntry: SystemAccountLedgerEntryProps = {
      id: BigInt(0), // 由数据库生成
      accountId: this._id,
      entryType: params.entryType,
      amount: params.amount,
      balanceAfter: newBalance,
      sourceOrderId: params.sourceOrderId || null,
      sourceRewardId: params.sourceRewardId || null,
      txHash: params.txHash || null,
      memo: params.memo || null,
      createdAt: new Date(),
    }

    this.addDomainEvent(
      new SystemAccountFundsReceivedEvent({
        accountId: this._id.toString(),
        accountType: this._accountType,
        amount: params.amount.toString(),
        entryType: params.entryType,
        balanceAfter: newBalance.toString(),
      }),
    )

    return ledgerEntry
  }

  /**
   * 转出资金
   */
  transferFunds(params: {
    amount: Decimal
    txHash?: string
    memo?: string
  }): SystemAccountLedgerEntryProps {
    if (!this.isActive) {
      throw new DomainError('系统账户已停用')
    }

    if (params.amount.lte(0)) {
      throw new DomainError('金额必须大于0')
    }

    if (this._usdtBalance.lt(params.amount)) {
      throw new DomainError('余额不足')
    }

    const newBalance = this._usdtBalance.minus(params.amount)
    this._usdtBalance = newBalance
    this._totalTransferred = this._totalTransferred.plus(params.amount)
    this._updatedAt = new Date()

    const ledgerEntry: SystemAccountLedgerEntryProps = {
      id: BigInt(0),
      accountId: this._id,
      entryType: SystemLedgerEntryType.TRANSFER_OUT,
      amount: params.amount.neg(),
      balanceAfter: newBalance,
      sourceOrderId: null,
      sourceRewardId: null,
      txHash: params.txHash || null,
      memo: params.memo || null,
      createdAt: new Date(),
    }

    this.addDomainEvent(
      new SystemAccountFundsTransferredEvent({
        accountId: this._id.toString(),
        accountType: this._accountType,
        amount: params.amount.toString(),
        txHash: params.txHash || null,
        balanceAfter: newBalance.toString(),
      }),
    )

    return ledgerEntry
  }

  /**
   * 增加算力
   */
  addHashpower(amount: Decimal): void {
    if (amount.lte(0)) {
      throw new DomainError('算力必须大于0')
    }

    this._hashpower = this._hashpower.plus(amount)
    this._updatedAt = new Date()
  }

  /**
   * 停用账户
   */
  deactivate(): void {
    this._status = SystemAccountStatus.INACTIVE
    this._updatedAt = new Date()
  }

  /**
   * 激活账户
   */
  activate(): void {
    this._status = SystemAccountStatus.ACTIVE
    this._updatedAt = new Date()
  }

  /**
   * 转换为持久化数据
   */
  toPersistence(): Record<string, any> {
    return {
      id: this._id,
      accountType: this._accountType,
      regionCode: this._regionCode,
      regionName: this._regionName,
      walletAddress: this._walletAddress,
      mpcPublicKey: this._mpcPublicKey,
      usdtBalance: this._usdtBalance,
      hashpower: this._hashpower,
      totalReceived: this._totalReceived,
      totalTransferred: this._totalTransferred,
      status: this._status,
      createdAt: this._createdAt,
      updatedAt: this._updatedAt,
    }
  }
}
