import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { TextInput } from '@inkjs/ui';
import { Box, Text } from 'ink';
import { useState } from 'react';
import { decodeAbiParameters, encodeAbiParameters } from 'viem';
import { z } from 'zod';
const preprocess = (type, value) => {
    // this one we should try to not throw errors, that is job of encodeAbiParameters
    // encodeAbiParameters has more descriptive errors, so we don't need to duplicate that here
    // it simply handles the following and returns everything else as is
    //
    // 1. ints that need to be cast to bigint
    // 2. booleans that need to be cast to true/false
    // 3. doesn't handle tuples or structs (TODO)
    if (type.startsWith('int') || type.startsWith('uint')) {
        const { success, data } = z.coerce.bigint().safeParse(value);
        if (!success)
            return value;
        return data;
    }
    if (type === 'bool') {
        if (value === 'true')
            return true;
        if (value === 'false')
            return false;
    }
    return value;
};
const validate = (abiParameter, value) => {
    const preprocessed = preprocess(abiParameter.type, value);
    const abiParameters = [abiParameter];
    // if it throws any errors in this process, we know it's invalid
    // @ts-expect-error - this is all runtime validation anyway
    const encoded = encodeAbiParameters(abiParameters, [preprocessed]);
    const decoded = decodeAbiParameters(abiParameters, encoded);
    return decoded[0];
};
export const AbiItemInput = ({ parameter, onSubmit, }) => {
    const [error, setError] = useState('');
    const [attemptCount, setAttemptCount] = useState(0);
    const handleSubmit = (val) => {
        try {
            const validated = validate(parameter, val);
            onSubmit(validated);
            setError('');
        }
        catch (err) {
            const error = err;
            setError('Invalid: ' + (error.shortMessage || error.message));
            setAttemptCount(count => count + 1);
        }
    };
    return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: error ? `❌ ${error}` : ' ' }), _jsx(TextInput, { onSubmit: handleSubmit }, `${attemptCount}`)] }));
};
export const AbiItemForm = ({ abiItem, onSubmit, }) => {
    const { inputs } = abiItem;
    const [values, setValues] = useState(new Array(inputs.length));
    const [currentIndex, setCurrentIndex] = useState(0);
    return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "blue", children: "\uD83D\uDCDD Enter function arguments" }) }), _jsx(Box, { flexDirection: "column", children: inputs.map((input, index) => (_jsx(Box, { children: _jsxs(Text, { children: [index === currentIndex ? '▶️ ' : '  ', _jsx(Text, { color: "green", children: input.name || 'unnamed' }), _jsxs(Text, { dimColor: true, children: [" (", input.type, ")"] }), values[index] ? (_jsxs(Text, { color: "cyan", children: [" = ", values[index]] })) : (_jsx(Text, { dimColor: true, children: " \u22EF" })), currentIndex > index && _jsx(Text, { color: "green", children: " \u2713" })] }) }, index))) }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Enter value for " }), _jsx(Text, { bold: true, color: "yellow", children: inputs[currentIndex]?.name || 'unnamed' })] }), _jsx(AbiItemInput, { parameter: inputs[currentIndex], onSubmit: value => {
                    const newValues = [...values];
                    newValues[currentIndex] = value;
                    if (currentIndex === inputs.length - 1) {
                        onSubmit(newValues);
                    }
                    else {
                        setValues(newValues);
                        setCurrentIndex(currentIndex + 1);
                    }
                } }, currentIndex)] }));
};
