import {
    Accordion,
    AccordionDetails,
    AccordionSummary,
    Box,
    Button,
    Typography,
    Skeleton,
    useTheme,
} from "@mui/material";
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { ChangeEvent, useState, useMemo, useEffect } from "react";
import { useNavigate, createSearchParams } from "react-router-dom";
import { useQuery } from "react-query";
import { formatCurrency, formatNumber } from "../../../helpers";
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber"
import { tokenNameConverter } from "../../../helpers/tokenConverter";
import { isNetworkLegacy } from "../../../constants";
import { EMPTY_ADDRESS } from "../../../constants/addresses";

import GhostStyledIcon from "../../Icon/GhostIcon";
import TokenStack from "../../TokenStack/TokenStack";
import { PrimaryButton, SecondaryButton } from "../../Button";

import { useBalance, useTokenSymbol } from "../../../hooks/tokens";
import {
    useNativePrice,
    useReservePrice,
    useFtsoPrice,
    useGhstPrice
} from "../../../hooks/prices";
import { useLpValuation } from "../../../hooks/treasury";
import { useUniswapV2PairReserves } from "../../../hooks/uniswapv2";
import { getTokenIcons } from "../../../hooks/helpers";
import { useAccount, useBalance as useNativeBalance, useConfig, useSwitchChain, useChainId } from "wagmi";

const addTokenToWallet = async (token, userAddress) => {
    if (!window.ethereum) return;
    try {
        await window.ethereum.request({
            method: "wallet_watchAsset",
            params: {
                type: "ERC20",
                options: {
                    address: token.address,
                    symbol: token.symbol,
                    decimals: token.balance._decimals,
                    image: token.externalUrl, // external host
                },
            },
        });
    } catch (error) {
        console.log(error);
    }
};

const BalanceValue = ({
    balance,
    balanceValueUSD,
    isLoading = false,
}) => (
    <Box sx={{ textAlign: "right", display: "flex", flexDirection: "column", justifyContent: "space-between" }}>
        <Typography variant="body2" style={{ fontWeight: 600 }}>
            {formatNumber(balance, 5)}
        </Typography>
        <Typography variant="body2" color="textSecondary">
            {formatCurrency(balanceValueUSD, 2)}
        </Typography>
    </Box>
);

export const Token = (props) => {
    const {
        isNative,
        symbol,
        faucetPath,
        icons,
        address,
        price = 0,
        balance,
        onAddTokenToWallet,
        expanded,
        onChangeExpanded,
        reserveAddress,
        onClose,
        isPool
    } = props;
    const theme = useTheme();
    const navigate = useNavigate();
    const chainId = useChainId();

    const { chains } = useSwitchChain();

    const chainName = useMemo(() => {
        return chains.find(chain => chain.id === chainId).name.toLowerCase();
    }, [chains, chainId])

    const useLink = (symbol, fromAddress, toAddress, isPool) => {
        if (faucetPath) {
            navigate({ pathname: faucetPath })
        } else {
            navigate({
                pathname: `${chainName}/dex/uniswap`,
                search: isPool ?
                    createSearchParams({
                        pool: "true",
                        from: `${fromAddress}`,
                        to: `${toAddress}`,
                    }).toString()
                    :
                    createSearchParams({
                        from: `${fromAddress}`,
                        to: `${toAddress}`,
                    }).toString()
            })
        }
        onClose();
    }

    return (
        <Accordion expanded={isNative ? false : expanded} onChange={onChangeExpanded}>
            <AccordionSummary
                sx={{ paddingRight: isNative ? "37.43px" : "" }}
                expandIcon={isNative ? null : <GhostStyledIcon component={ExpandMoreIcon} color="disabled" />}
            >
                <Box sx={{ display: "flex", justifyContent: "space-between", width: "100%", marginRight: "10px" }}>
                    <Box sx={{ display: "flex", alignItems: "center", gap: "15px" }}>
                        <TokenStack
                            style={{
                                width: "28px",
                                height: "28px",
                            }}
                            tokens={props.icons}
                        />
                        <Typography>{symbol}</Typography>
                    </Box>
                    <BalanceValue
                        balance={balance}
                        balanceValueUSD={balance.mul(price)}
                    />
                </Box>
            </AccordionSummary>
            {!isNative && <AccordionDetails style={{ margin: "auto", padding: theme.spacing(1, 0) }}>
                <Box
                    sx={{ display: "flex", flexDirection: "column", flex: 1, mx: "32px", justifyContent: "center" }}
                    style={{ gap: theme.spacing(1) }}
                >
                    <Box display="flex" flexDirection="column" className="ghst-pairs" style={{ width: "100%" }}>
                        <PrimaryButton
                            onClick={onAddTokenToWallet}
                            fullWidth
                        >
                            <Typography>Add to Wallet</Typography>
                        </PrimaryButton>
                        <SecondaryButton
                            onClick={() => useLink(symbol, reserveAddress, address, isPool)}
                            fullWidth
                        >
                            <Typography>Get {faucetPath ? "for Free" : "on DEX"}</Typography>
                        </SecondaryButton>
                    </Box>
                </Box>
            </AccordionDetails>}
        </Accordion>
    );
};

const sumObjValues = (obj: Record<string, string> = {}) =>
    Object.values(obj).reduce((sum, b = "0.0") => sum + (parseFloat(b) || 0), 0);

export const useWallet = (chainId, userAddress) => {
    const {
        data: nativeBalanceRaw,
        refetch: nativeBalanceRefetch
    } = useNativeBalance({ address: userAddress });
    const nativeBalance = new DecimalBigNumber(nativeBalanceRaw?.value ?? 0n, 18);
    const {
        balance: reserveBalance,
        refetch: reserveRefetch,
        contractAddress: reserveAddress,
    } = useBalance(chainId, "RESERVE", userAddress);
    const {
        balance: ftsoBalance,
        refetch: ftsoRefetch,
        contractAddress: ftsoAddress,
    } = useBalance(chainId, "FTSO", userAddress);
    const {
        balance: ghstBalance,
        refetch: ghstRefetch,
        contractAddress: ghstAddress,
    } = useBalance(chainId, "GHST", userAddress);
    const {
        balance: lpReserveFtsoBalance,
        refetch: lpReserveFtsoRefetch,
        contractAddress: lpReserveFtsoBalanceAddress,
    } = useBalance(chainId, "RESERVE_FTSO", userAddress);
    const {
        tokens: lpReserveFtsoTokens,
    } = useUniswapV2PairReserves(chainId, "RESERVE_FTSO");

    const nativePrice = useNativePrice(chainId);
    const reservePrice = useReservePrice(chainId);
    const ftsoPrice = useFtsoPrice(chainId);
    const ghstPrice = useGhstPrice(chainId);
    const lpReserveFtsoPrice = useLpValuation(chainId, "RESERVE_FTSO", 1000000000000000000n);

    const config = useConfig();

    const nativeSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
    const { symbol: reserveSymbol } = useTokenSymbol(chainId, "RESERVE");
    const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO");
    const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
    const { symbol: lpReserveFtsoSymbol } = useTokenSymbol(chainId, "RESERVE_FTSO");

    const lpReserveFtsoTokenNames = useMemo(() => {
        const token0 = getTokenIcons(chainId, lpReserveFtsoTokens?.token0 ?? []);
        const token1 = getTokenIcons(chainId, lpReserveFtsoTokens?.token1 ?? []);

        let tokenAddresses = [lpReserveFtsoTokens?.token1, lpReserveFtsoTokens?.token0];
        let tokenNames = [...token1, ...token0];

        if (token0?.at(0) === reserveSymbol) {
            tokenAddresses =  [lpReserveFtsoTokens?.token0, lpReserveFtsoTokens?.token1];
            let tokenNames = [...token0, ...token1];
        }

        return { tokenAddresses, tokenNames }
    }, [chainId, reserveSymbol, lpReserveFtsoTokens]);

    const tokens = {
        native: {
            symbol: nativeSymbol,
            icons: [nativeSymbol],
            balance: nativeBalance,
            price: nativePrice,
            refetch: nativeBalanceRefetch,
        },
        reserve: {
            symbol: reserveSymbol,
            address: reserveAddress,
            balance: reserveBalance,
            price: reservePrice,
            icons: isNetworkLegacy(chainId) ? ["GDAI"] : [tokenNameConverter(chainId, reserveSymbol)],
            externalUrl: isNetworkLegacy(chainId)
                ? "https://ghostchain.io/wp-content/uploads/2025/03/gDAI.svg"
                : "https://ghostchain.io/wp-content/uploads/2025/11/6A-Classic-ETC-Token.svg",
            refetch: reserveRefetch,
        },
        ftso: {
            symbol: ftsoSymbol,
            address: ftsoAddress,
            balance: ftsoBalance,
            price: ftsoPrice,
            icons: ["FTSO"],
            externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/eGHST.svg",
            refetch: ftsoRefetch,
        },
        ghst: {
            symbol: ghstSymbol,
            address: ghstAddress,
            balance: ghstBalance,
            price: ghstPrice,
            icons: ["GHST"],
            externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/GHST.svg",
            refetch: ghstRefetch,
        },
        reserveFtso: {
            isPool: true,
            symbol: lpReserveFtsoSymbol,
            address: lpReserveFtsoTokenNames?.tokenAddresses.at(1) ?? "",
            balance: lpReserveFtsoBalance,
            price: lpReserveFtsoPrice,
            icons: lpReserveFtsoTokenNames?.tokenNames,
            externalUrl: "https://ghostchain.io/wp-content/uploads/2025/03/uni-v2.svg",
            refetch: lpReserveFtsoRefetch,
        }
    };

    return Object.entries(tokens).reduce((wallet, [key, token]) => {
        return {
            ...wallet,
            [key]: {
                ...token,
                totalBalance: "0",
            },
        };
    }, {});
};

export const Tokens = ({ address, tokens, onClose }) => {
    const [expanded, setExpanded] = useState(null);
    const alwaysShowTokens = [tokens.native, tokens.reserve, tokens.ftso, tokens.ghst, tokens.reserveFtso];

    const tokenProps = (token) => ({
        ...token,
        expanded: expanded === token.symbol,
        reserveAddress: EMPTY_ADDRESS,
        onChangeExpanded: (e, isExpanded) => setExpanded(isExpanded ? token.symbol : null),
        onAddTokenToWallet: () => addTokenToWallet(token, address),
        onClose: () => onClose(),
    });

    return (
        <>
            {alwaysShowTokens.map((token, i) => (
                <Token key={i} isNative={i === 0} {...tokenProps(token)} />
            ))}
        </>
    );
};
