import { useState, useEffect, useMemo } from "react";
import { Box, Container, Typography, useMediaQuery } from "@mui/material";
import { useConfig, useBalance } from "wagmi";
import { Helmet } from "react-helmet";
import ReactGA from "react-ga4";

import PageTitle from "../../components/PageTitle/PageTitle";
import Paper from "../../components/Paper/Paper";
import SwapCard from "../../components/Swap/SwapCard";
import TokenStack from "../../components/TokenStack/TokenStack";
import { PrimaryButton } from "../../components/Button";
import { Tab, Tabs } from "../../components/Tabs/Tabs";

import { RESERVE_ADDRESSES } from "../../constants/addresses";
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { formatCurrency, formatNumber } from "../../helpers";

import {
    useBalance as useTokenBalance,
    useTokenSymbol,
    useTotalSupply,
    useConversionRate,
    useAccumulatedDonation,
    mintDai,
    burnDai
} from "../../hooks/tokens";

const Faucet = ({ chainId, address, config, connect }) => {
    const isSmallScreen = useMediaQuery("(max-width: 650px)");
    const isSemiSmallScreen = useMediaQuery("(max-width: 480px)");
    const isVerySmallScreen = useMediaQuery("(max-width: 379px)");

    const [isMint, setIsMint] = useState(true);
    const [isPending, setIsPending] = useState(false);
    const [balance, setBalance] = useState(new DecimalBigNumber(0, 0));
    const [amount, setAmount] = useState("");
    const [scanInfo, setScanInfo] = useState({
        name: "",
        url: "",
    });
    const [nativeInfo, setNativeInfo] = useState({
        decimals: 18,
        name: "",
        symbol: "",
    })

    const reserveConversionRate = useConversionRate(chainId, "RESERVE");
    const accumulatedDonation = useAccumulatedDonation(chainId, "RESERVE");

    const { balance: reserveBalance, refetch: reserveBalanceRefetch } = useTokenBalance(chainId, "RESERVE", address);
    const { data: nativeBalance, refetch: balanceRefetch } = useBalance({ address });
    const { data: contractBalance, refetch: contractBalanceRefetch } = useBalance({ address: RESERVE_ADDRESSES[chainId] });
    const { totalSupply: reserveTotalSupply, refetch: refetchReserveTotalSupply } = useTotalSupply(chainId, "RESERVE");
    const { symbol: reserveSymbol } = useTokenSymbol(chainId, "RESERVE");

    useEffect(() => {
        ReactGA.send({ hitType: "pageview", page: "/faucet" });
    }, [])

    useEffect(() => {
        const value = nativeBalance ? nativeBalance.value : 0n;
        const decimals = nativeBalance ? nativeBalance.decimals : 18;
        setBalance(new DecimalBigNumber(value, decimals));
    }, [nativeBalance]);

    useEffect(() => {
        let scanName = "";
        let scanUrl = "";

        const client = config?.getClient();
        scanName = client?.chain?.blockExplorers?.default?.name;
        scanUrl = client?.chain?.blockExplorers?.default?.url;

        setScanInfo({
            name: scanName,
            url: scanUrl,
        })

        setNativeInfo(client?.chain?.nativeCurrency)
    }, [chainId]);

    const changeIsMinted = (value) => {
        if (accumulatedDonation) {
            setAmount("");
            setIsMint(value);
        }
    }

    const preparedAmount = useMemo(() => {
        if (address === "") new DecimalBigNumber("0", 0);
        const decimals = isMint ? nativeInfo.decimals : 18;
        return new DecimalBigNumber(amount, decimals);
    }, [amount, balance, nativeInfo])

    const estimatedAmountIn = useMemo(() => {
        const rate = new DecimalBigNumber(reserveConversionRate.toString(), 0);
        const value = new DecimalBigNumber(amount, nativeInfo.decimals);
        return value.mul(rate);
    }, [amount, reserveConversionRate, nativeInfo]);

    const contractBalanceFree = useMemo(() => {
        const realContractBalance = contractBalance ? contractBalance.value : 0n;
        const preparedContractBalance = new DecimalBigNumber(realContractBalance, nativeInfo.decimals);
        const preparedAccumulatedDonation = new DecimalBigNumber(
            accumulatedDonation._value,
            nativeInfo.decimals && 18
        );
        return preparedContractBalance.sub(preparedAccumulatedDonation);
    }, [contractBalance, accumulatedDonation]);

    const estimatedAmountOut = useMemo(() => {
        const value = new DecimalBigNumber(amount, nativeInfo.decimals);
        if (reserveTotalSupply._value > 0n) {
            return value.mul(contractBalanceFree).div(reserveTotalSupply);
        }
        return new DecimalBigNumber(0n, nativeInfo.decimals);
    }, [amount, contractBalanceFree, reserveTotalSupply, nativeInfo]);

    const actionOrConnect = async () => {
        if (address === "") {
            connect();
        } else {
            setIsPending(true);

            if (isMint) {
                await mintDai(chainId, address, preparedAmount._value.toString());
            } else {
                await burnDai(chainId, address, preparedAmount._value.toString());
            }

            await balanceRefetch();
            await reserveBalanceRefetch();
            await contractBalanceRefetch();
            await refetchReserveTotalSupply();
            setAmount("");
            setIsPending(false);
        }
    }

    return (
        <Box height="calc(100vh - 43px)">
            <Helmet>
                <title>ghostFaucet | gDAI Faucet</title>
                <meta name="description" content="ghostFaucet is a No KYC gDAI Faucet powered by GHOST. Get gDAI sent directly to your wallet." />
                <meta name="keywords" content="ghostFaucet, web3 faucet, gDAI, ethereum, sepolia, polygon, bnb, bsc, AVAX" />

                <meta property="og:image" content="https://ghostchain.io/wp-content/uploads/2025/03/ghostFaucet-Featured_Image.png" />
                <meta property="og:title" content="ghostDAO | The DeFi 2.0 cross-chain reserve currency" />
                <meta property="og:image:type" content="image/png" />
                <meta property="og:image:width" content="1200" />
                <meta property="og:image:height" content="630" />
                <meta property="og:type" content="website" />
                <meta property="og:description" content="ghostFaucet is a No KYC gDAI Faucet powered by GHOST. Get gDAI sent directly to your wallet." />

                <meta name="twitter:card" content="summary" />
                <meta name="twitter:site" content="@realGhostChain" />
                <meta name="twitter:title" content="ghostDAO | The DeFi 2.0 cross-chain reserve currency" />
                <meta name="twitter:description" content="ghostFaucet is a No KYC gDAI Faucet powered by GHOST. Get gDAI sent directly to your wallet." />
                <meta name="twitter:image" content="https://ghostchain.io/wp-content/uploads/2025/03/ghostFaucet-Featured_Image.png" />
            </Helmet>

            <PageTitle name={`${reserveSymbol} Faucet`} subtitle={`Swap Sepolia ${nativeInfo.symbol} for ${reserveSymbol}.`} />
            <Container
                style={{
                    paddingLeft: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
                    paddingRight: isSmallScreen || isVerySmallScreen ? "0" : "3.3rem",
                    display: "flex",
                    justifyContent: "center",
                    alignItems: "center",
                    height: "calc(100vh - 153px)"
                }}
            >
                <Box width="100%" maxWidth="476px" display="flex" alignItems="center" justifyContent="center" flexDirection="column">
                    <Paper
                        headerContent={
                            <Box alignItems="center" justifyContent="space-between" display="flex" width="100%">
                                <Tabs
                                    centered
                                    textColor="primary"
                                    indicatorColor="primary"
                                    value={isMint ? 0 : 1}
                                    aria-label="Faucet menu"
                                    onChange={(_, view) => changeIsMinted(view === 0)}
                                    TabIndicatorProps={{ style: { display: "none" } }}
                                >
                                    <Tab aria-label="faucet-mint-button" label="Mint" style={{ fontSize: "1.5rem" }} />
                                    {accumulatedDonation && <Tab aria-label="faucet-burn-button" label="Burn" style={{ fontSize: "1.5rem" }} />}
                                </Tabs>
                                {!isSemiSmallScreen && <PrimaryButton
                                    variant="text"
                                    href={`${scanInfo.url}/token/${RESERVE_ADDRESSES[chainId]}`}
                                >
                                    Check on {scanInfo.name}
                                </PrimaryButton>}
                            </Box>
                        }
                        enableBackground
                        fullWidth
                    >
                        <Box>
                            {isMint && <SwapCard
                                id={`faucet-sepolia-eth`}
                                inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
                                tokenName={nativeInfo.symbol}
                                token={<TokenStack tokens={[nativeInfo.symbol]} sx={{ fontSize: "21px" }} />}
                                info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(balance.toString(), 4, nativeInfo.symbol)}`}
                                value={amount}
                                onChange={event => setAmount(event.currentTarget.value)}
                                inputProps={{ "data-testid": "fromInput" }}
                            />}
                            {!isMint && <SwapCard
                                id={`faucet-sepolia-eth`}
                                inputWidth={isVerySmallScreen ? "100px" : isSemiSmallScreen ? "180px" : "250px"}
                                tokenName={reserveSymbol}
                                token={<TokenStack tokens={[reserveSymbol]} sx={{ fontSize: "21px" }} />}
                                info={`${formatCurrency(reserveBalance.toString(), 4, reserveSymbol)}`}
                                value={amount}
                                onChange={event => setAmount(event.currentTarget.value)}
                                inputProps={{ "data-testid": "fromInput" }}
                                endString={"Max"}
                                endStringOnClick={() => setAmount(reserveBalance.toString())}
                            />}
                        <Box
                            mb="20px"
                            mt="20px"
                            flexDirection="column"
                            display="flex"
                            justifyContent="space-between"
                        >
                                {isMint && (
                                    <>
                                        <Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
                                            {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">{nativeInfo.symbol} multiplier:</Typography>}
                                            <Typography fontSize="12px" lineHeight="15px">{formatNumber(reserveConversionRate, 2)}</Typography>
                                        </Box>
                                        <Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
                                            {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">You will get:</Typography>}
                                            <Typography fontSize="12px" lineHeight="15px">{formatCurrency(estimatedAmountIn, 5, reserveSymbol)}</Typography>
                                        </Box>
                                        <Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
                                            {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {reserveSymbol} balance:</Typography>}
                                            <Typography fontSize="12px" lineHeight="15px">{formatCurrency(reserveBalance, 5, reserveSymbol)}</Typography>
                                        </Box>
                                    </>
                                )}
                                {!isMint && (
                                    <>
                                        <Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
                                            {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Accumulated {nativeInfo.symbol}:</Typography>}
                                            <Typography fontSize="12px" lineHeight="15px">{formatCurrency(contractBalanceFree, 5, nativeInfo.symbol)}</Typography>
                                        </Box>
                                        <Box maxWidth="416px" display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
                                            {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">You will get:</Typography>}
                                            <Typography fontSize="12px" lineHeight="15px">{formatCurrency(estimatedAmountOut, 5, nativeInfo.symbol)}</Typography>
                                        </Box>
                                        <Box display="flex" justifyContent={isVerySmallScreen ? "end" : "space-between"}>
                                            {!isVerySmallScreen && <Typography fontSize="12px" lineHeight="15px">Your {nativeInfo.symbol} balance:</Typography>}
                                            <Typography fontSize="12px" lineHeight="15px">{formatCurrency(balance, 5, nativeInfo.symbol)}</Typography>
                                        </Box>
                                    </>
                                )}
                            </Box>
                            <PrimaryButton
                                fullWidth
                                disabled={
                                    address !== "" && (
                                        preparedAmount?._value === 0n ||
                                        isPending ||
                                        (isMint && balance?.lt(preparedAmount)) ||
                                        (!isMint && reserveBalance?.lt(preparedAmount))
                                    )
                                }
                                loading={isPending}
                                onClick={() => actionOrConnect()}
                            >
                                {address === "" ?
                                    "Connect"
                                    :
                                    isMint ? "Mint" : "Burn"
                                }
                            </PrimaryButton>
                        </Box>
                    </Paper>
                </Box>
            </Container>
        </Box>
    )
}

export default Faucet;
