/**
 * Copyright (c) TonTech.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

import { useCallback, useMemo, useState } from 'react';
import type { FC, ComponentProps } from 'react';
import clsx from 'clsx';

import { useI18n } from '../../../settings/hooks/use-i18n';
import { useSelectedWallet } from '../../../wallets';
import { SwapConfirmModal } from '../swap-confirm-modal';
import { SwapField } from '../swap-field';
import { SwapFlipButton } from '../swap-flip-button';
import { SwapInfo } from '../swap-info';
import { SwapSettingsModal } from '../swap-settings-modal';
import { SwapTokenSelectModal } from '../swap-token-select-modal';
import { LowBalanceModal } from '../../../../components/shared/low-balance-modal';
import styles from './swap-widget-ui.module.css';
import type { SwapContextType } from '../swap-widget-provider';
import { ButtonWithConnect } from '../../../../components/shared/button-with-connect';
import { SettingsButton } from '../../../../components/shared/settings-button';

export type SwapWidgetRenderProps = SwapContextType & ComponentProps<'div'>;

export const SwapWidgetUI: FC<SwapWidgetRenderProps> = ({
    fromToken,
    toToken,
    tokens,
    fromAmount,
    toAmount,
    fiatSymbol,
    fromBalance,
    toBalance,
    isFromBalanceLoading,
    isToBalanceLoading,
    canSubmit,
    quote,
    isQuoteLoading,
    error,
    slippage,
    swapProvider,
    swapProviders,
    setSwapProviderId,
    onFlip,
    onMaxClick,
    setFromAmount,
    setFromToken,
    setToToken,
    setSlippage,
    sendSwapTransaction,
    isSendingTransaction,
    isLowBalanceWarningOpen,
    lowBalanceMode,
    lowBalanceRequiredTon,
    onLowBalanceChange,
    onLowBalanceCancel,
    className,
    ...props
}) => {
    const [wallet] = useSelectedWallet();
    const isWalletConnected = wallet !== null;

    const { t } = useI18n();

    const [activeField, setActiveField] = useState<'from' | 'to' | null>(null);
    const [isSettingsOpen, setIsSettingsOpen] = useState(false);
    const [isConfirmOpen, setIsConfirmOpen] = useState(false);
    const [isFlipped, setIsFlipped] = useState(false);

    const handleFlip = useCallback(() => {
        setIsFlipped((prev) => !prev);
        onFlip();
    }, [onFlip]);

    // Close the modal immediately; the build/send result (including errors) is surfaced
    // back in the widget's main button via the `error` from the provider.
    const handleConfirm = useCallback(() => {
        setIsConfirmOpen(false);
        sendSwapTransaction().catch(() => {
            // Error is captured by the mutation and shown through the validator's `error` output.
        });
    }, [sendSwapTransaction]);

    const buttonText = useMemo(() => {
        if (isSendingTransaction || isQuoteLoading) return t('swap.loading');
        if (!fromToken || !toToken) return t('swap.selectToken');
        if (error) return t(error);
        if (canSubmit) return t('swap.continue');
        return t('swap.enterAmount');
    }, [isSendingTransaction, isQuoteLoading, error, fromToken, toToken, canSubmit, t]);

    return (
        <div className={clsx(styles.widget, className)} {...props}>
            <div className={styles.fieldsContainer}>
                <SwapField
                    type="pay"
                    token={fromToken ?? undefined}
                    amount={fromAmount}
                    onAmountChange={setFromAmount}
                    balance={fromBalance}
                    isBalanceLoading={isFromBalanceLoading}
                    onMaxClick={onMaxClick}
                    onTokenSelectorClick={() => setActiveField('from')}
                    isWalletConnected={isWalletConnected}
                    fiatSymbol={fiatSymbol}
                />

                <div className={styles.flipButtonWrapper}>
                    <div className={styles.flipButtonSeparator} />
                    <SwapFlipButton className={styles.flipButton} onClick={handleFlip} rotated={isFlipped} />
                </div>

                <SwapField
                    type="receive"
                    token={toToken ?? undefined}
                    amount={toAmount}
                    balance={toBalance}
                    isBalanceLoading={isToBalanceLoading}
                    onTokenSelectorClick={() => setActiveField('to')}
                    loading={isQuoteLoading}
                    isWalletConnected={isWalletConnected}
                    fiatSymbol={fiatSymbol}
                />
            </div>

            <SwapTokenSelectModal
                open={activeField !== null}
                onClose={() => setActiveField(null)}
                tokens={tokens}
                onSelect={(token) => {
                    if (activeField === 'from') setFromToken(token);
                    else setToToken(token);
                }}
            />

            <SwapSettingsModal
                open={isSettingsOpen}
                onClose={() => setIsSettingsOpen(false)}
                slippage={slippage}
                onSlippageChange={setSlippage}
                provider={swapProvider}
                providers={swapProviders}
                onProviderChange={setSwapProviderId}
            />

            <SwapConfirmModal
                open={isConfirmOpen}
                onClose={() => setIsConfirmOpen(false)}
                onConfirm={handleConfirm}
                fromToken={fromToken}
                toToken={toToken}
                fromAmount={fromAmount}
                toAmount={toAmount}
                fiatSymbol={fiatSymbol}
                quote={quote}
                swapProvider={swapProvider}
                slippage={slippage}
                isQuoteLoading={isQuoteLoading}
            />

            <LowBalanceModal
                open={isLowBalanceWarningOpen}
                mode={lowBalanceMode}
                requiredTon={lowBalanceRequiredTon}
                onChange={onLowBalanceChange}
                onCancel={onLowBalanceCancel}
            />

            <div className={styles.actions}>
                <ButtonWithConnect
                    variant="fill"
                    size="l"
                    fullWidth
                    disabled={!canSubmit || isQuoteLoading || isSendingTransaction}
                    onClick={() => setIsConfirmOpen(true)}
                >
                    {buttonText}
                </ButtonWithConnect>
                <SettingsButton onClick={() => setIsSettingsOpen(true)} />
            </div>

            <SwapInfo
                quote={quote}
                provider={swapProvider}
                toToken={toToken}
                slippage={slippage}
                isQuoteLoading={isQuoteLoading}
            />
        </div>
    );
};
