import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useQueryClient } from '@tanstack/react-query'
import {
  useJumperTokens, useWalletBalance, useWalletAddresses, useFetchJumperQuote, useExecuteBridge,
  type Chain, type JumperToken, type WalletBalanceData, type JumperQuote,
} from '@features/wallet'
import { Notification, PrimaryButton } from '@shared/ui'
import { ROUTES } from '@shared/config/routes'
import { toBaseUnits } from '@shared/lib/utils/baseUnits'
import {
  TOKEN_META, buildTokensFromBalance, useSwapForm,
  type Token,
} from '../../swap-form/model/useSwapForm'
import { SwapCard } from '../../swap-form/ui/SwapCard'
import { NetworkSelect } from './NetworkSelect'
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])
)

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 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 parsedAmount = parseFloat(fromAmount)
  const canQuote = !!fromJumper && !!toJumper && !!fromAddress && !!toAddress && parsedAmount > 0

  function handleConfirm() {
    if (!fromJumper || !toJumper || !fromAddress || !toAddress) return
    setErrorMessage(null)
    fetchQuote(
      {
        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,
      },
      {
        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={setFromNetwork}
        options={NETWORKS.filter(n => n !== toNetwork)}
      />
      <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="0"
        onTokenChange={setToToken}
        hideNetworkSelect
      />

      <PrimaryButton label="Подтвердить бридж" onClick={handleConfirm} disabled={!canQuote || isPending} />

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

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