import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { useQueryClient } from '@tanstack/react-query'
import { Notification, PrimaryButton } from '@shared/ui'
import {
  useWalletBalance, useWalletAddresses, useTokensList,
  useRelayQuote, useExecuteRelaySwap, useSignSwap,
  useTrxSwapQuote, useFetchTrxQuote, useExecuteTrxSwap,
  type Chain, type RelaySwapResponse, type TrxSwapQuoteData,
} from '@features/wallet'
import { ROUTES } from '@shared/config/routes'
import { useDebounce } from '@shared/lib/hooks/useDebounce'
import { TOKENS_LIST, buildTokensFromBalance, useSwapForm } from '../model/useSwapForm'
import { SwapCard } from './SwapCard'
import { SwapDirectionButton } from './SwapDirectionButton'
import { SwapInfoPanel } from './SwapInfoPanel'
import { SwapConfirmModal } from './SwapConfirmModal'
import { TrxConfirmModal } from './TrxConfirmModal'
import styles from './SwapForm.module.css'

const CHAIN_ID: Record<string, number> = { ETH: 1, BSC: 56, SOL: 792703809 }
const NATIVE_ADDR: Record<string, string> = {
  SOL: '11111111111111111111111111111111',
  DEFAULT: '0x0000000000000000000000000000000000000000',
}
function nativeAddr(chain: string) {
  return NATIVE_ADDR[chain] ?? NATIVE_ADDR.DEFAULT
}

export function SwapForm() {
  const navigate = useNavigate()
  const queryClient = useQueryClient()

  const {
    fromAmount, fromUsd,
    fromToken, toToken,
    setFromAmount, setPercent, swapTokens,
    setFromToken, setToToken,
  } = useSwapForm()

  const [fromNetwork, setFromNetwork] = useState('ETH')
  const [modalData, setModalData] = useState<RelaySwapResponse | null>(null)
  const [trxModalQuote, setTrxModalQuote] = useState<TrxSwapQuoteData | null>(null)
  const [errorMessage, setErrorMessage] = useState<string | null>(null)

  const isTrxNetwork = fromNetwork === 'TRX'

  const { data: walletData } = useWalletBalance(fromNetwork as Chain)
  const tokenOptions = walletData ? buildTokensFromBalance(walletData) : TOKENS_LIST

  useEffect(() => {
    if (tokenOptions.length === 0) return
    setFromToken(t => tokenOptions.find(o => o.symbol === t.symbol) ?? tokenOptions[0])
    setToToken(t => tokenOptions.find(o => o.symbol === t.symbol) ?? (tokenOptions[1] ?? tokenOptions[0]))
  }, [walletData, fromNetwork])

  const debouncedAmount = useDebounce(fromAmount, 500)
  const { data: addresses } = useWalletAddresses()
  const { data: tokensList } = useTokensList()

  const parsedAmount = parseFloat(debouncedAmount)

  // ── Relay (ETH / BSC / SOL) ─────────────────────────────────────────────
  const chainId = CHAIN_ID[fromNetwork]
  const walletAddress = addresses?.find(a => a.chain === fromNetwork)?.address
  const fromContract = tokensList?.find(t => t.chain === fromNetwork && t.symbol === fromToken.symbol)?.contract ?? nativeAddr(fromNetwork)
  const toContract = tokensList?.find(t => t.chain === fromNetwork && t.symbol === toToken.symbol)?.contract ?? nativeAddr(fromNetwork)

  const quotePayload = !isTrxNetwork && chainId && walletAddress && parsedAmount > 0
    ? {
      user: walletAddress,
      recipient: walletAddress,
      originChainId: chainId,
      destinationChainId: chainId,
      originCurrency: fromContract,
      destinationCurrency: toContract,
      amount: Math.round(parsedAmount * Math.pow(10, fromToken.decimals)).toString(),
      tradeType: 'EXACT_INPUT' as const,
    }
    : null

  const { data: quoteData } = useRelayQuote(quotePayload)
  const { mutate: executeSwap, isPending: isSwapping } = useExecuteRelaySwap()
  const { mutate: signSwap, isPending: isSigning } = useSignSwap()

  // ── TRX ─────────────────────────────────────────────────────────────────
  const trxQuotePayload = isTrxNetwork && parsedAmount > 0
    ? { from: fromToken.symbol, to: toToken.symbol, amountHuman: debouncedAmount }
    : null

  const { data: trxQuoteData } = useTrxSwapQuote(trxQuotePayload)
  const { mutate: fetchTrxQuote, isPending: isFetchingTrxQuote } = useFetchTrxQuote()
  const { mutate: executeTrxSwap, isPending: isExecutingTrxSwap } = useExecuteTrxSwap()

  const isProcessing = isSigning || isExecutingTrxSwap

  const insufficientBalance = (parseFloat(fromAmount) || 0) > fromToken.balance

  // ── Display values ───────────────────────────────────────────────────────
  const displayToAmount = isTrxNetwork
    ? (trxQuoteData?.expectedOutFormatted ?? '0')
    : (quoteData?.details.currencyOut.amountFormatted ?? '0')

  const displayToUsd = isTrxNetwork
    ? undefined
    : quoteData?.details.currencyOut.amountUsd

  const gasFee = isTrxNetwork
    ? trxQuoteData?.fees.network.amountUsd?.toString()
    : quoteData?.fees.gas.amountUsd

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

  const isButtonDisabled = isTrxNetwork
    ? parsedAmount <= 0 || isFetchingTrxQuote
    : !quotePayload || isSwapping

  function handleSwap() {
    if (isTrxNetwork) {
      if (!trxQuotePayload) return
      fetchTrxQuote(trxQuotePayload, {
        onSuccess: (quote) => setTrxModalQuote(quote),
      })
    } else {
      if (!quotePayload) return
      executeSwap(quotePayload, {
        onSuccess: (data) => setModalData(data),
      })
    }
  }

  return (
    <div className={styles.form}>
      <SwapCard
        mode="from"
        token={fromToken}
        tokenOptions={tokenOptions}
        amount={fromAmount}
        usd={fromUsd}
        onAmountChange={setFromAmount}
        onSetPercent={setPercent}
        onTokenChange={setFromToken}
        selectedNetwork={fromNetwork}
        onNetworkChange={setFromNetwork}
      />

      <SwapDirectionButton onClick={swapTokens} />

      <SwapCard
        mode="to"
        token={toToken}
        tokenOptions={tokenOptions}
        amount={displayToAmount}
        usd={displayToUsd}
        onTokenChange={setToToken}
      />

      <SwapInfoPanel gasFee={gasFee} serviceFee={serviceFee} serviceFeeToken={serviceFeeToken} />

      <PrimaryButton
        label={isSwapping || isFetchingTrxQuote ? 'Загрузка...' : undefined}
        onClick={handleSwap}
        disabled={isButtonDisabled}
      />

      {modalData && (
        <SwapConfirmModal
          data={modalData}
          insufficientBalance={insufficientBalance}
          onClose={() => setModalData(null)}
          onConfirm={() => {
            const txData = modalData.steps[0]?.items[0]?.data
            if (txData) {
              setErrorMessage(null)
              signSwap(
                { chain: fromNetwork as Chain, txData },
                {
                  onSuccess: () => {
                    queryClient.invalidateQueries({ queryKey: ['wallet', 'balance', fromNetwork] })
                    queryClient.invalidateQueries({ queryKey: ['wallet', 'portfolio'] })
                    navigate(`${ROUTES.WALLET}/${fromNetwork.toLowerCase()}`)
                  },
                  onError: (err) => {
                    setErrorMessage(err instanceof Error ? err.message : 'Не удалось подписать транзакцию')
                  },
                },
              )
            }
            setModalData(null)
          }}
        />
      )}

      {trxModalQuote && (
        <TrxConfirmModal
          quote={trxModalQuote}
          fromSymbol={fromToken.symbol}
          toSymbol={toToken.symbol}
          amountHuman={fromAmount}
          insufficientBalance={insufficientBalance}
          onClose={() => setTrxModalQuote(null)}
          onConfirm={() => {
            setErrorMessage(null)
            executeTrxSwap(trxModalQuote.quoteId, {
              onSuccess: () => {
                queryClient.invalidateQueries({ queryKey: ['wallet', 'balance', 'TRX'] })
                queryClient.invalidateQueries({ queryKey: ['wallet', 'portfolio'] })
                navigate(`${ROUTES.WALLET}/${fromNetwork.toLowerCase()}`)
              },
              onError: (err) => {
                setErrorMessage(err instanceof Error ? err.message : 'Не удалось выполнить свап')
              },
            })
            setTrxModalQuote(null)
          }}
        />
      )}

      {isProcessing && (
        <Notification
          status="warning"
          message="Обработка транзакции..."
          onClose={() => { }}
        />
      )}

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