import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useQueryClient } from '@tanstack/react-query'
import {
  useJumperTokens, useWalletBalance, useWalletAddresses, useFetchJumperQuote, useExecuteBridge,
  useRelayQuote,
  type Chain, type JumperToken, type WalletBalanceData, type JumperQuote, type JumperQuotePayload,
  type RelayQuotePayload,
} from '@features/wallet'
import { Notification, PrimaryButton } from '@shared/ui'
import { ROUTES } from '@shared/config/routes'
import { useDebounce } from '@shared/lib/hooks/useDebounce'
import { toBaseUnits, fromBaseUnits } from '@shared/lib/utils/baseUnits'
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
import {
  TOKEN_META, buildTokensFromBalance, useSwapForm,
  type Token,
} from '../../swap-form/model/useSwapForm'
import { SwapCard } from '../../swap-form/ui/SwapCard'
import { NetworkSelect } from './NetworkSelect'
import { BridgeInfoPanel } from './BridgeInfoPanel'
import { BridgeConfirmModal } from './BridgeConfirmModal'
import styles from './BridgeForm.module.css'

const NETWORKS = ['ETH', 'BSC', 'SOL', 'TRX', 'BTC']

const CHAIN_ID_BY_NET: Record<string, string> = {
  ETH: '1',
  BSC: '56',
  SOL: '1151111081099710',
  TRX: '728126428',
  BTC: '20000000000001',
}

const NET_BY_CHAIN_ID: Record<string, string> = Object.fromEntries(
  Object.entries(CHAIN_ID_BY_NET).map(([net, id]) => [id, net])
)

// Relay использует собственные chain id (отличаются от Jumper, напр. для SOL)
const RELAY_CHAIN_ID: Record<string, number> = {
  ETH: 1,
  BSC: 56,
  SOL: 792703809,
  TRX: 728126428,
  BTC: 8253038,
}

function mapJumperToken(t: JumperToken): Token {
  const meta = TOKEN_META[t.symbol]
  return {
    symbol: t.symbol,
    letter: meta?.letter ?? t.symbol[0],
    color: meta?.color ?? '#888',
    logo: t.logoURI ?? meta?.logo,
    network: NET_BY_CHAIN_ID[String(t.chainId)] ?? t.symbol,
    balance: 0,
    usdRate: parseFloat(t.priceUSD) || 0,
    decimals: t.decimals,
  }
}

function balanceBySymbol(data: WalletBalanceData): Record<string, number> {
  const map: Record<string, number> = {}
  for (const t of buildTokensFromBalance(data)) map[t.symbol] = t.balance
  return map
}

export function BridgeForm() {
  const navigate = useNavigate()
  const queryClient = useQueryClient()
  const {
    fromAmount, fromUsd,
    fromToken, toToken,
    setFromAmount, setPercent,
    setFromToken, setToToken,
  } = useSwapForm()

  const [fromNetwork, setFromNetwork] = useState('ETH')
  const [toNetwork, setToNetwork] = useState('BSC')
  const [quote, setQuote] = useState<JumperQuote | null>(null)
  const [errorMessage, setErrorMessage] = useState<string | null>(null)

  const { data: jumperData } = useJumperTokens()
  const { data: fromWalletData } = useWalletBalance(fromNetwork as Chain)
  const { data: toWalletData } = useWalletBalance(toNetwork as Chain)
  const { data: addresses } = useWalletAddresses()
  const { mutate: fetchQuote, isPending } = useFetchJumperQuote()
  const { mutate: executeBridge, isPending: isExecuting } = useExecuteBridge()

  function optionsFor(network: string, walletData?: WalletBalanceData): Token[] {
    const list = (jumperData?.[CHAIN_ID_BY_NET[network]] ?? []).map(mapJumperToken)
    if (!walletData) return list
    const balances = balanceBySymbol(walletData)
    return list.map(t => (balances[t.symbol] != null ? { ...t, balance: balances[t.symbol] } : t))
  }

  const fromTokenOptions = optionsFor(fromNetwork, fromWalletData)
  const toTokenOptions = optionsFor(toNetwork, toWalletData)

  useEffect(() => {
    if (fromTokenOptions.length === 0) return
    setFromToken(t => fromTokenOptions.find(o => o.symbol === t.symbol) ?? fromTokenOptions[0])
  }, [jumperData, fromWalletData, fromNetwork])

  useEffect(() => {
    if (toTokenOptions.length === 0) return
    setToToken(t => toTokenOptions.find(o => o.symbol === t.symbol) ?? toTokenOptions[0])
  }, [jumperData, toWalletData, toNetwork])

  const parsedAmount = parseFloat(fromAmount)

  const insufficientBalance = (parsedAmount || 0) > fromToken.balance

  const fromJumper = jumperData?.[CHAIN_ID_BY_NET[fromNetwork]]?.find(t => t.symbol === fromToken.symbol)
  const toJumper = jumperData?.[CHAIN_ID_BY_NET[toNetwork]]?.find(t => t.symbol === toToken.symbol)
  const fromAddress = addresses?.find(a => a.chain === fromNetwork)?.address
  const toAddress = addresses?.find(a => a.chain === toNetwork)?.address

  const quotePayload: JumperQuotePayload | null =
    fromJumper && toJumper && fromAddress && toAddress && parsedAmount > 0
      ? {
        fromChain: CHAIN_ID_BY_NET[fromNetwork],
        toChain: CHAIN_ID_BY_NET[toNetwork],
        fromToken: fromJumper.address,
        toToken: toJumper.address,
        fromAmount: toBaseUnits(fromAmount, fromToken.decimals),
        fromAddress,
        toAddress,
        slippage: 0.005,
      }
      : null

  // Реактивная оценка суммы назначения через /api/relay/quote (как в SwapForm)
  const debouncedAmount = useDebounce(fromAmount, 500)
  const parsedDebounced = parseFloat(debouncedAmount)
  const relayOriginChainId = RELAY_CHAIN_ID[fromNetwork]
  const relayDestChainId = RELAY_CHAIN_ID[toNetwork]

  const relayQuotePayload: RelayQuotePayload | null =
    fromJumper && toJumper && fromAddress && toAddress &&
      relayOriginChainId && relayDestChainId && parsedDebounced > 0
      ? {
        user: fromAddress,
        recipient: toAddress,
        originChainId: relayOriginChainId,
        destinationChainId: relayDestChainId,
        originCurrency: fromJumper.address,
        destinationCurrency: toJumper.address,
        amount: toBaseUnits(debouncedAmount, fromToken.decimals),
        tradeType: 'EXACT_INPUT',
      }
      : null

  const { data: relayQuote } = useRelayQuote(relayQuotePayload)

  const serviceFee = relayQuote?.appCommission?.usd?.toString()
  const serviceFeeToken = relayQuote?.appCommission?.inToken

  const displayToAmount = relayQuote
    ? relayQuote.details.currencyOut.amountFormatted
    : quote
      ? truncateDecimals(fromBaseUnits(quote.estimate.toAmount, quote.action.toToken.decimals), 8)
      : '0'

  function handleFromNetworkChange(net: string) {
    setFromNetwork(net)
    // сеть назначения не может совпадать с исходной — переключаем на первую доступную
    if (net === toNetwork) {
      setToNetwork(NETWORKS.find(n => n !== net) ?? toNetwork)
    }
  }

  function handleConfirm() {
    if (!quotePayload) return
    setErrorMessage(null)
    fetchQuote(quotePayload, {
      onSuccess: (q) => setQuote(q),
      onError: (err) => setErrorMessage(err instanceof Error ? err.message : 'Не удалось получить котировку'),
    })
  }

  function handleExecute() {
    if (!quote) return
    setErrorMessage(null)
    executeBridge(
      {
        provider: 'jumper',
        fromChain: quote.action.fromChainId,
        toChain: quote.action.toChainId,
        fromToken: quote.action.fromToken.address,
        toToken: quote.action.toToken.address,
        fromAmount: quote.action.fromAmount,
        fromAddress: quote.action.fromAddress,
        toAddress: quote.action.toAddress,
        acceptedMinOut: quote.estimate.toAmountMin,
      },
      {
        onSuccess: () => {
          queryClient.invalidateQueries({ queryKey: ['wallet', 'balance', fromNetwork] })
          queryClient.invalidateQueries({ queryKey: ['wallet', 'balance', toNetwork] })
          queryClient.invalidateQueries({ queryKey: ['wallet', 'portfolio'] })
          setQuote(null)
          navigate(ROUTES.WALLET)
        },
        onError: (err) => setErrorMessage(err instanceof Error ? err.message : 'Не удалось выполнить бридж'),
      },
    )
  }

  if (!jumperData) {
    return <div className={styles.form} />
  }

  return (
    <div className={styles.form}>
      <NetworkSelect
        label="ИЗ"
        value={fromNetwork}
        onChange={handleFromNetworkChange}
        options={NETWORKS}
      />
      <SwapCard
        mode="from"
        token={fromToken}
        tokenOptions={fromTokenOptions}
        amount={fromAmount}
        usd={fromUsd}
        onAmountChange={setFromAmount}
        onSetPercent={setPercent}
        onTokenChange={setFromToken}
        hideNetworkSelect
      />

      <NetworkSelect
        label="В"
        value={toNetwork}
        onChange={setToNetwork}
        options={NETWORKS.filter(n => n !== fromNetwork)}
      />
      <SwapCard
        mode="to"
        token={toToken}
        tokenOptions={toTokenOptions}
        amount={displayToAmount}
        onTokenChange={setToToken}
        hideNetworkSelect
      />

      <BridgeInfoPanel serviceFee={serviceFee} serviceFeeToken={serviceFeeToken} />

      <PrimaryButton label={isPending ? 'Загрузка...' : 'Подтвердить бридж'} onClick={handleConfirm} disabled={!quotePayload || isPending} />

      {quote && (
        <BridgeConfirmModal
          quote={quote}
          fromAmountHuman={fromAmount}
          insufficientBalance={insufficientBalance}
          isExecuting={isExecuting}
          onConfirm={handleExecute}
          onClose={() => setQuote(null)}
        />
      )}

      {errorMessage && (
        <Notification
          status="error"
          message={errorMessage}
          onClose={() => setErrorMessage(null)}
        />
      )}
    </div>
  )
}
