import { ref, computed } from 'vue'
import UniversalProvider from '@walletconnect/universal-provider'
import { WalletConnectModal } from '@walletconnect/modal'
import { TronWeb, Types } from 'tronweb'
import {
  TRON_MAINNET_CAIP2,
  TRON_MAINNET_CHAIN_ID_HEX,
  isTronDepositNetwork,
  parseTronCaip10Address,
  tronMainnetCaip10Account,
  isTronRechargeUsdtSymbol,
  TRC20_USDT_OFFICIAL_MAINNET,
  TRC20_USDT_DECIMALS,
  trc20AmountToMinUnits,
  trxToSunAmount,
} from '@/utils/tronRecharge'
import type { RechargeFlatNetworkOption, RechargeOrderDetail } from '@/stores/deposit'

const FEE_LIMIT_SUN = 150_000_000

let tronProviderInit: Promise<UniversalProvider> | null = null
let wcModal: WalletConnectModal | null = null
let displayUriHandler: ((uri: string) => void) | null = null

function getProjectId(): string {
  return String(import.meta.env.VITE_WALLETCONNECT_PROJECT_ID ?? '').trim()
}

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 }
}

function closeTronWcModal() {
  wcModal?.closeModal()
}

function ensureWcModal(projectId: string): WalletConnectModal {
  if (!wcModal && typeof window !== 'undefined') {
    wcModal = new WalletConnectModal({
      projectId,
      themeMode: 'dark',
      themeVariables: { '--wcm-z-index': '3000' },
    })
  }
  return wcModal!
}

function attachDisplayUri(provider: UniversalProvider, projectId: string) {
  const modal = ensureWcModal(projectId)
  if (displayUriHandler) {
    provider.off('display_uri', displayUriHandler)
  }
  displayUriHandler = (uri: string) => {
    void modal.openModal({ uri, chains: [TRON_MAINNET_CAIP2] })
  }
  provider.on('display_uri', displayUriHandler)
}

async function getTronProvider(): Promise<UniversalProvider> {
  const projectId = getProjectId()
  if (!projectId) {
    throw new Error('未配置 VITE_WALLETCONNECT_PROJECT_ID')
  }
  if (!tronProviderInit) {
    tronProviderInit = UniversalProvider.init({
      projectId,
      metadata: {
        name: 'iBit',
        description: '链上充值（波场）',
        url: typeof window !== 'undefined' ? window.location.origin : 'https://ibit.com',
        icons: [],
      },
    })
  }
  const provider = await tronProviderInit
  attachDisplayUri(provider, projectId)
  return provider
}

function firstTronAddress(provider: UniversalProvider): string {
  const raw = provider.session?.namespaces?.tron?.accounts ?? []
  for (const a of raw) {
    const addr = parseTronCaip10Address(String(a))
    if (addr) {
      return addr
    }
  }
  throw new Error('未获取到波场钱包地址')
}

/** 钱包校验时常要求 address 与 session.accounts 中某条完全一致（CAIP-10） */
function tronSessionAccountString(provider: UniversalProvider, base58: string): string {
  const accounts = provider.session?.namespaces?.tron?.accounts ?? []
  for (const a of accounts) {
    const s = String(a)
    if (parseTronCaip10Address(s) === base58) {
      return s
    }
  }
  return tronMainnetCaip10Account(base58)
}

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）')
}

/**
 * 与 @tronweb3/walletconnect-tron 一致：v1 为扁平 transaction；非 v1 为 transaction: { transaction }。
 * address 须为 Base58（T…），不要用整条 CAIP-10 作为 address。
 */
function tronSessionUsesSignV1(provider: UniversalProvider): boolean {
  const v = provider.session?.sessionProperties?.tron_method_version
  return v === 'v1'
}

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

  const paramVariants: unknown[] = []

  if (useV1) {
    // v1（session 明确声明）：扁平结构，address = Base58
    paramVariants.push({ address: fromBase58, transaction: prepared })
    paramVariants.push({ transaction: prepared })
    paramVariants.push({ address: fromBase58, transaction: { transaction: prepared } })
    paramVariants.push({ address: sessionAcct, transaction: prepared })
    // 兜底：不带 txID
    paramVariants.push({ address: fromBase58, transaction: noTxId })
    paramVariants.push({ transaction: noTxId })
  } else {
    // 非 v1（默认）：嵌套结构优先，与 @tronweb3/walletconnect-tron adapter 一致
    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 })
    // 兜底：不带 txID（少数钱包拒绝 txID 校验）
    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 provider.request(
        {
          method: 'tron_signTransaction',
          params,
        } as never,
        TRON_MAINNET_CAIP2,
      )
      return normalizeTronSignedResult(out)
    } catch (e) {
      lastErr = e
      console.debug(
        `[tron_signTransaction] variant ${i} 失败：`,
        formatWalletConnectError(e),
        '| params keys:',
        params && typeof params === 'object' && !Array.isArray(params)
          ? Object.keys(params as object).join(',')
          : Array.isArray(params)
            ? `Array[${(params as unknown[]).length}]`
            : typeof params,
      )
    }
  }
  const msg = formatWalletConnectError(lastErr)
  throw new Error(`tron_signTransaction 失败（已尝试多种参数格式）。最后错误：${msg}`)
}

/**
 * 若当前已恢复的会话只有 eip155 等非 tron 命名空间，UniversalProvider 不会自动再连；
 * 若无可用 tron 账户则断开并重新用 tron 命名空间建连。
 */
async function ensureTronWalletConnectSession(provider: UniversalProvider): Promise<void> {
  const raw = provider.session?.namespaces?.tron?.accounts ?? []
  const hasParsed = raw.some((a) => parseTronCaip10Address(String(a)) != null)

  if (provider.session && !hasParsed) {
    await provider.disconnect()
  }

  if (!provider.session) {
    await provider.connect({
      namespaces: {
        tron: {
          methods: ['tron_signTransaction', 'tron_signMessage'],
          chains: [TRON_MAINNET_CAIP2],
          events: [],
          rpcMap: {
            [TRON_MAINNET_CHAIN_ID_HEX]: tronFullHost(),
          },
        },
      },
      // 是否 v1 由钱包在回包里写入 sessionProperties；强行写 v1 可能与部分钱包参数形状不一致
    } as Parameters<UniversalProvider['connect']>[0])
  }
}

export function useWalletConnectTronDeposit() {
  const wcTronBusy = ref(false)
  const wcTronConfigured = computed(() => !!getProjectId())

  function resetTronWalletBusy() {
    wcTronBusy.value = false
    closeTronWcModal()
  }

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

  /**
   * WalletConnect（tron 命名空间）签名并广播：TRC20 transfer 或原生 TRX 转账。
   * @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('当前订单或网络不支持波场 WalletConnect')
    }
    wcTronBusy.value = true
    try {
      const provider = await getTronProvider()
      const tronWeb = new TronWeb({
        fullHost: tronFullHost(),
        headers: tronHeaders(),
      })

      await ensureTronWalletConnectSession(provider)

      const from = firstTronAddress(provider)
      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(provider, from, unsigned)
      closeTronWcModal()

      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,
    canPayTronWithWallet,
    connectAndPayTron,
  }
}
