import { useRef, useMemo, useState } from "react";
import { Box, Typography, Link, TableCell, TableRow, useTheme } from "@mui/material";
import { decodeFunctionData } from 'viem';
import toast from "react-hot-toast";

import { StyledInputBase } from "../../../../components/Swap/SwapCard";
import { TertiaryButton } from "../../../../components/Button";
import InfoTooltip from "../../../../components/Tooltip/InfoTooltip";

import { abi as TreasuryAbi } from "../../../../abi/GhostTreasury.json";
import { abi as DistributorAbi } from "../../../../abi/GhostDistributor.json";
import { abi as DepositoryAbi } from "../../../../abi/GhostBondDepository.json";

import { config } from "../../../../config";
import { shorten, formatCurrency } from "../../../../helpers";

import { prepareAuditReservesDescription, prepareAuditReservesCalldata, AuditReservesSteps, AuditReservesParsed } from "./AuditReserves";
import { prepareSetAdjustmentDescription, prepareSetAdjustmentCalldata, SetAdjustmentSteps, SetAdjustmentParsed } from "./SetAdjustment";
import { prepareCreateBondDescription, prepareCreateBondCalldata, CreateBondSteps, CreateBondParsed } from "./CreateBond";

const DEFAULT_DESCRIPTION = "Please select the function to include in your proposal. Multi-functional proposals are allowed, but each included function should be clearly specified."

export const allPossibleFunctions = [
    { value: "auditReserves", label: "auditReserves" },
    { value: "setAdjustment", label: "setAdjustment"     },
    { value: "create",        label: "create"    },
];

const allAbis = [TreasuryAbi, DistributorAbi, DepositoryAbi];

const identifyAction = (calldata) => {
    let decoded = { functionName: "Unknown", args: [] };
    for (const abi of allAbis) {
        try {
            decoded = decodeFunctionData({
                abi: abi,
                data: calldata,
            });
            return decoded;
        } catch (err) {
            continue;
        }
    }
    return decoded;
}

export const parseFunctionCalldata = (metadata, index, chainId, nativeCoin, removeCalldata) => {
    const { label, calldata, target, value } = metadata;
    const { functionName, args } = identifyAction(calldata);
    const labelOrName = label ?? (functionName ?? "Unknown");

    const remove = removeCalldata && (() => removeCalldata(index));

    switch (functionName) {
        case "auditReserves":
            return <AuditReservesParsed
                isTable
                key={index}
                calldata={calldata}
                label={labelOrName}
                chainId={chainId}
                remove={remove}
                nativeCoin={nativeCoin}
                value={value}
                target={target}
                id={index}
            />;
        case "setAdjustment":
            return <SetAdjustmentParsed
                isTable
                args={args}
                key={index}
                calldata={calldata}
                label={labelOrName}
                chainId={chainId}
                remove={remove}
                nativeCoin={nativeCoin}
                value={value}
                target={target}
                id={index}
            />;
        case "create":
            return <CreateBondParsed
                isTable
                args={args}
                key={index}
                calldata={calldata}
                label={labelOrName}
                chainId={chainId}
                remove={remove}
                nativeCoin={nativeCoin}
                value={value}
                target={target}
                id={index}
            />;
        default:
            return <ParsedCell
                isTable
                key={index}
                calldata={calldata}
                label="Unknown"
                remove={remove}
                nativeCoin={nativeCoin}
                value={value}
                target={target}
                id={index}
            />;
    }
}

export const getFunctionArguments = (functionName) => {
    switch (functionName) {
        case "auditReserves":
            return null;
        case "setAdjustment":
            return SetAdjustmentSteps;
        case "create":
            return CreateBondSteps;
        default:
            return null;
    }
}

export const getFunctionCalldata = (functionName, chainId) => {
    switch (functionName) {
        case "auditReserves":
            return prepareAuditReservesCalldata(chainId);
        case "setAdjustment":
            return prepareSetAdjustmentCalldata(chainId);
        case "create":
            return prepareCreateBondCalldata(chainId);
        default:
            return null;
    }
}

export const getFunctionDescription = (functionName) => {
    switch (functionName) {
        case "auditReserves":
            return prepareAuditReservesDescription;
        case "setAdjustment":
            return prepareSetAdjustmentDescription;
        case "create":
            return prepareCreateBondDescription;
        default:
            return DEFAULT_DESCRIPTION;
    }
}

export const BooleanValue = ({ left, text, isSelected, setSelected }) => {
    const theme = useTheme();
    return (
        <Box
            onClick={() => setSelected()}
            display="flex"
            justifyContent="center"
            alignItems="center"
            sx={{
                cursor: "pointer",
                borderRadius: left ? "12px 0 0 12px" : "0 12px 12px 0",
                flex: 1,
                border: "2px solid #fff",
                borderLeft: left ? "2px solid #fff" : "none",
                borderRight: left ? "none" : "2px solid #fff",
                background: `${isSelected ? "#fff" : theme.colors.gray[600] }`
            }}
        >
            <Typography
                color={isSelected ? theme.colors.gray[600] : "#fff"}
                align="center"
            >
                {text}
            </Typography>
        </Box>
    )
}

export const ArgumentsWrapper = ({ label, tooltip, children }) => {
    return (
        <Box sx={{ marginBottom: "18px" }}>
            <Box sx={{ marginLeft: "5px", marginBottom: "5px" }} display="flex" flexDirection="row" alignItems="center">
                <Typography>{label}</Typography>
                <InfoTooltip message={tooltip} />
            </Box>
            {children}
        </Box>
    )
}

export const BooleanTrigger = ({ value, label, tooltip, leftText, rightText, setLeftValue, setRightValue }) => {
    return (
        <ArgumentsWrapper label={label} tooltip={tooltip}>
            <Box display="flex" width="100%" height="40px">
                <BooleanValue setSelected={setLeftValue} left isSelected={value} text={leftText} />
                <BooleanValue setSelected={setRightValue} isSelected={!value} text={rightText} />
            </Box>
        </ArgumentsWrapper>
    )
}

export const ArgumentInput = ({
    endString,
    label,
    tooltip,
    value,
    setValue,
    disabled,
    inputType = "number",
    placeholder = "0",
    maxWidth = "100%"
}) => {
    const theme = useTheme();
    const ref = useRef(null);

    return (
        <Box sx={{ marginBottom: "15px" }}>
            <Box sx={{ marginLeft: "5px", marginBottom: "5px" }} display="flex" flexDirection="row" alignItems="center">
                <Typography>{label}</Typography>
                <InfoTooltip message={tooltip} />
            </Box>
            <Box
                display="flex"
                flexDirection="column"
                maxWidth={maxWidth}
                sx={{ backgroundColor: theme.colors.gray[750] }}
                borderRadius="12px"
                padding="6px"
                onClick={() => {
                    ref.current && ref.current.focus();
                }}
            >
                <Box width="100%" display="flex" flexDirection="row" justifyContent="space-between" alignItems="center">
                    <StyledInputBase
                        disabled={disabled}
                        placeholder={placeholder}
                        type={inputType}
                        fontSize="20px"
                        value={value}
                        onChange={(e) => setValue(e.target.value)}
                        sx={{ flex: 1 }}
                    />
                    {endString && (
                        <Box sx={{ paddingRight: "10px", color: theme.colors.gray[500] }} fontSize="12px" lineHeight="15px">
                            {endString}
                        </Box>
                    )}
                </Box>
            </Box>
        </Box>
    )
}

export const ParsedCell = (props) => {
    const [isCopied, setIsCopied] = useState(false);

    const etherscanLink = useMemo(() => {
        const client = config.getClient();
        let url = client?.chain?.blockExplorers?.default?.url;
        if (url) {
            url = url + `/address/${props.target}`;
        }
        return url;
    }, [props, config]);

    const handleCalldataCopy = async () => {
        try {
            await navigator.clipboard.writeText(props.calldata);
            setIsCopied(true);
            toast.success("Calldata successfully copied to your clipboard.", { duration: 2000 });

            setTimeout(() => setIsCopied(false), 2000);
        } catch (err) {
            toast.error("Could not copy calldata to clipboard, check logs for error details.", { duration: 5000 });
            console.error(err);
        }
    };

    return (
        <TableRow id={props.id + `--proposalFunction`} data-testid={props.id + `--proposalFunction`}>
            <TableCell align="center" style={{ padding: "8px 0" }}>
                <Typography>{props.label}</Typography>
            </TableCell>

            <TableCell align="center" style={{ padding: "8px 0" }}>
                <Link href={etherscanLink} target="_blank" rel="noopener noreferrer">
                    <Typography>{shorten(props.target)}</Typography>
                </Link>
            </TableCell>

            <TableCell align="center" style={{ padding: "8px 0" }}>
                <Link onClick={handleCalldataCopy} target="_blank" rel="noopener noreferrer">
                    <Typography>{shorten(props.calldata)}</Typography>
                </Link>
            </TableCell>

            <TableCell align="center" style={{ padding: "8px 0" }}>
                <Typography>{formatCurrency(props.value, 4, props.nativeCoin)}</Typography>
            </TableCell>

            <TableCell>
                <div style={{ display: 'flex', gap: '8px' }}>
                    {props.args && <TertiaryButton fullWidth onClick={() => props.setIsOpened(!props.isOpened)}>View</TertiaryButton>}
                    {props.remove && <TertiaryButton fullWidth onClick={() => props.remove()}>Delete</TertiaryButton>}
                </div>
            </TableCell>
        </TableRow>
    )
}
