import { ref, computed } from 'vue'
import { TronWeb, Types } from 'tronweb'
import { tronMainnet } from '@reown/appkit/networks'
import {
  TRON_MAINNET_CAIP2,
  isTronDepositNetwork,
  tronMainnetCaip10Account,
  isTronRechargeUsdtSymbol,
  TRC20_USDT_OFFICIAL_MAINNET,
  TRC20_USDT_DECIMALS,
  trc20AmountToMinUnits,
  trxToSunAmount,
} from '@/utils/tronRecharge'
import { getReownAppKit, reownAppKit, reownEnabled } from '@/config/reownAppKit'
import {
  abortActiveTronConnectWait,
  waitForTronConnectAfterModalOpen,
} from '@/utils/reownConnectWait'
import type { RechargeFlatNetworkOption, RechargeOrderDetail } from '@/stores/deposit'

const FEE_LIMIT_SUN = 150_000_000

type TronProviderRequest = (args: { method: string; params?: unknown }) => Promise<unknown>

interface TronWalletConnector {
  request?: TronProviderRequest
  provider?: {
    session?: {
      sessionProperties?: Record<string, unknown>
    }
    request?: (args: { method: string; params?: unknown }, chainId?: string) => Promise<unknown>
  }
}

function tronFullHost(): string {
  const h = String(import.meta.env.VITE_TRON_FULL_HOST ?? '').trim()
  return h || 'https://api.trongrid.io'
}

function tronHeaders(): Record<string, string> | undefined {
  const key = String(import.meta.env.VITE_TRONGRID_API_KEY ?? '').trim()
  if (!key) {
    return undefined
  }
  return { 'TRON-PRO-API-KEY': key }
}

async function ensureTronConnected(): Promise<string> {
  const appKit = getReownAppKit()
  try {
    await appKit.switchNetwork(tronMainnet)
  } catch {
    // 已处于波场网络时可忽略
  }

  const existing = appKit.getAccount('tron')
  if (existing?.isConnected && existing.address) {
    return existing.address
  }

  await appKit.open({ namespace: 'tron', view: 'Connect' })
  return waitForTronConnectAfterModalOpen()
}

export async function resetTronWalletSession() {
  abortActiveTronConnectWait()
  if (!reownEnabled) {
    return
  }
  try {
    await reownAppKit?.close()
    await reownAppKit?.disconnect('tron')
  } catch {
    // Reset is best-effort; the next click will create a fresh session.
  }
}

function getTronConnector(): TronWalletConnector {
  const connector = getReownAppKit().getProvider<TronWalletConnector>('tron')
  if (!connector) {
    throw new Error('波场钱包未连接')
  }
  return connector
}

function sanitizeUnsignedTxForWc(tx: Types.Transaction): Record<string, unknown> {
  const plain = JSON.parse(JSON.stringify(tx)) as Record<string, unknown>
  delete plain.signature
  return plain
}

function prepareUnsignedForTronWalletConnect(tx: Types.Transaction): Record<string, unknown> {
  const o = sanitizeUnsignedTxForWc(tx)
  const rd = o.raw_data
  if (rd && typeof rd === 'object' && !Array.isArray(rd)) {
    const raw = rd as Record<string, unknown>
    const contracts = raw.contract
    if (Array.isArray(contracts)) {
      for (const c of contracts) {
        if (c && typeof c === 'object' && !Array.isArray(c)) {
          const con = c as Record<string, unknown>
          if (con.Permission_id === undefined) {
            con.Permission_id = 0
          }
        }
      }
    }
  }
  return o
}

function cloneWithoutTxId(tx: Record<string, unknown>): Record<string, unknown> {
  const c = JSON.parse(JSON.stringify(tx)) as Record<string, unknown>
  delete c.txID
  return c
}

function formatWalletConnectError(e: unknown): string {
  if (e instanceof Error && e.message) {
    return e.message
  }
  if (typeof e === 'string') {
    return e
  }
  if (e && typeof e === 'object') {
    const o = e as Record<string, unknown>
    if (typeof o.message === 'string') {
      return o.message
    }
    if (typeof o.msg === 'string') {
      return o.msg
    }
    if (typeof o.reason === 'string') {
      return o.reason
    }
    const data = o.data
    if (data && typeof data === 'object') {
      const d = data as Record<string, unknown>
      if (typeof d.message === 'string') {
        return d.message
      }
    }
    try {
      return JSON.stringify(e)
    } catch {
      return Object.prototype.toString.call(e)
    }
  }
  return String(e)
}

function normalizeTronSignedResult(raw: unknown): Types.SignedTransaction {
  let cur: unknown = raw
  if (typeof cur === 'string') {
    try {
      cur = JSON.parse(cur) as unknown
    } catch {
      throw new Error('钱包返回的签名格式无效')
    }
  }
  if (!cur || typeof cur !== 'object') {
    throw new Error('钱包未返回签名数据')
  }
  const r = cur as Record<string, unknown>
  if (r.result !== undefined && r.result !== null && typeof r.result === 'object') {
    return normalizeTronSignedResult(r.result)
  }
  if (Array.isArray(r.signature) && r.signature.length > 0 && r.raw_data && typeof r.raw_data === 'object') {
    return cur as Types.SignedTransaction
  }
  for (const k of ['transaction', 'signedTransaction', 'tx']) {
    const inner = r[k]
    if (inner && typeof inner === 'object') {
      try {
        return normalizeTronSignedResult(inner)
      } catch {
        /* 尝试下一包裹字段 */
      }
    }
  }
  throw new Error('钱包未返回有效签名（signature）')
}

function tronSessionUsesSignV1(connector: TronWalletConnector): boolean {
  const v = connector.provider?.session?.sessionProperties?.tron_method_version
  return v === 'v1'
}

async function requestTronSignTransaction(
  fromBase58: string,
  unsigned: Types.Transaction,
): Promise<Types.SignedTransaction> {
  const connector = getTronConnector()
  const prepared = prepareUnsignedForTronWalletConnect(unsigned)
  const noTxId = cloneWithoutTxId(prepared)
  const sessionAcct = tronMainnetCaip10Account(fromBase58)
  const useV1 = tronSessionUsesSignV1(connector)

  const requestViaConnector = async (args: { method: string; params?: unknown }) => {
    if (connector.request) {
      return connector.request(args)
    }
    if (connector.provider?.request) {
      return connector.provider.request(args, TRON_MAINNET_CAIP2)
    }
    throw new Error('波场钱包不支持签名请求')
  }

  try {
    const injectedSigned = await requestViaConnector({
      method: 'tron_sendTransaction',
      params: { transaction: prepared },
    })
    return normalizeTronSignedResult(injectedSigned)
  } catch (injectedErr) {
    console.debug('[tron_sendTransaction] 注入钱包签名失败：', formatWalletConnectError(injectedErr))
  }

  const paramVariants: unknown[] = []
  if (useV1) {
    paramVariants.push({ address: fromBase58, transaction: prepared })
    paramVariants.push({ transaction: prepared })
    paramVariants.push({ address: fromBase58, transaction: { transaction: prepared } })
    paramVariants.push({ address: sessionAcct, transaction: prepared })
    paramVariants.push({ address: fromBase58, transaction: noTxId })
    paramVariants.push({ transaction: noTxId })
  } else {
    paramVariants.push({ address: fromBase58, transaction: { transaction: prepared } })
    paramVariants.push({ address: fromBase58, transaction: prepared })
    paramVariants.push({ transaction: { transaction: prepared } })
    paramVariants.push({ transaction: prepared })
    paramVariants.push({ address: sessionAcct, transaction: { transaction: prepared } })
    paramVariants.push({ address: sessionAcct, transaction: prepared })
    paramVariants.push({ address: fromBase58, transaction: { transaction: noTxId } })
    paramVariants.push({ address: fromBase58, transaction: noTxId })
    paramVariants.push({ transaction: { transaction: noTxId } })
    paramVariants.push({ transaction: noTxId })
  }

  let lastErr: unknown
  for (let i = 0; i < paramVariants.length; i++) {
    const params = paramVariants[i]
    try {
      const out = await requestViaConnector({
        method: 'tron_signTransaction',
        params,
      })
      return normalizeTronSignedResult(out)
    } catch (e) {
      lastErr = e
      console.debug(
        `[tron_signTransaction] variant ${i} 失败：`,
        formatWalletConnectError(e),
      )
    }
  }
  const msg = formatWalletConnectError(lastErr)
  throw new Error(`tron_signTransaction 失败（已尝试多种参数格式）。最后错误：${msg}`)
}

export function useWalletConnectTronDeposit() {
  const wcTronBusy = ref(false)
  const wcTronConfigured = computed(() => reownEnabled && reownAppKit != null)

  function resetTronWalletBusy() {
    wcTronBusy.value = false
    void resetTronWalletSession()
  }

  function canPayTronWithWallet(
    network: RechargeFlatNetworkOption | null,
    order: RechargeOrderDetail | null,
  ): boolean {
    if (!network || !order || Number(order.status) !== 0) {
      return false
    }
    return isTronDepositNetwork(network.protocol, network.networkName)
  }

  /**
   * 通过 Reown AppKit（TronLink / MetaMask Tron / WalletConnect）签名并广播。
   * @returns 链上 txid（与手动填写的 TxID 一致，非 0x 以太坊 hash）
   */
  async function connectAndPayTron(params: {
    network: RechargeFlatNetworkOption
    order: RechargeOrderDetail
  }): Promise<string> {
    const { network, order } = params
    if (!canPayTronWithWallet(network, order)) {
      throw new Error('当前订单或网络不支持波场钱包支付')
    }
    if (!reownEnabled) {
      throw new Error('未配置 VITE_WALLETCONNECT_PROJECT_ID')
    }

    wcTronBusy.value = true
    try {
      const from = await ensureTronConnected()
      const tronWeb = new TronWeb({
        fullHost: tronFullHost(),
        headers: tronHeaders(),
      })

      const to = order.rechargeAddress.trim()
      if (!to || !to.startsWith('T')) {
        throw new Error('收款地址不是有效的波场地址')
      }
      const amountStr = String(order.amount).trim()

      let contract = network.contractAddress?.trim() ?? ''
      if (
        !contract &&
        (isTronRechargeUsdtSymbol(network.coinName) || isTronRechargeUsdtSymbol(order.coinName))
      ) {
        contract = TRC20_USDT_OFFICIAL_MAINNET
      }

      let unsigned: Types.Transaction

      if (contract) {
        const param = [
          { type: 'address', value: to },
          { type: 'uint256', value: trc20AmountToMinUnits(amountStr, TRC20_USDT_DECIMALS) },
        ]
        const built = await tronWeb.transactionBuilder.triggerSmartContract(
          contract,
          'transfer(address,uint256)',
          { feeLimit: FEE_LIMIT_SUN, callValue: 0 },
          param,
          from,
        )
        if (!built.result?.result) {
          throw new Error(built.result?.message || '构建 TRC20 交易失败')
        }
        unsigned = built.transaction
      } else {
        unsigned = await tronWeb.transactionBuilder.sendTrx(to, trxToSunAmount(amountStr), from)
      }

      const signed = await requestTronSignTransaction(from, unsigned)
      await reownAppKit?.close()

      const broadcast = await tronWeb.trx.broadcast(signed)
      if (!broadcast.result || !broadcast.txid) {
        throw new Error(broadcast.message || '广播交易失败')
      }
      return broadcast.txid
    } finally {
      wcTronBusy.value = false
    }
  }

  return {
    wcTronBusy,
    wcTronConfigured,
    resetTronWalletBusy,
    clearTronWalletSession: resetTronWalletSession,
    canPayTronWithWallet,
    connectAndPayTron,
  }
}
