import {
    IconButton,
    InputLabel,
    MenuItem,
    Select,
    Tooltip,
} from '@mui/material';
import { orange, purple, red, yellow } from '@mui/material/colors';
import MergeTypeIcon from '@mui/icons-material/MergeType';
import SaveIcon from '@mui/icons-material/Save';
import SendIcon from '@mui/icons-material/Send';
import VpnKeyIcon from '@mui/icons-material/VpnKey';
import * as Bitcoin from 'bitcoinjs-lib';
import React from 'react';
import Hex from './Hex';
import './PSBTDetail.css';
interface IProps {
    psbts: Bitcoin.Psbt[];
}
class PSBTHandler {
    show_flash: (
        msg: string | JSX.Element,
        color: string,
        onclick?: () => void
    ) => void;
    constructor(
        show_flash: (
            msg: string | JSX.Element,
            color: string,
            onclick?: () => void
        ) => void
    ) {
        this.show_flash = show_flash;
    }
    async combine_psbt(psbt: Bitcoin.Psbt) {
        const psbt_in: Bitcoin.Psbt = Bitcoin.Psbt.fromBase64(
            await window.electron.fetch_psbt()
        );
        try {
            psbt.combine(psbt_in);
            this.show_flash('PSBT Combined', 'green');
        } catch (e: any) {
            this.show_flash(
                <div>
                    PSBT Error{' '}
                    <span className="glyphicon glyphicon-question-sign"></span>
                </div>,
                'red',
                () => alert(e.toString())
            );
        }
    }
    async sign_psbt(psbt: string) {
        const command = [{ method: 'walletprocesspsbt', parameters: [psbt] }];
        const signed = (await window.electron.bitcoin_command(command))[0];
        const as_psbt = Bitcoin.Psbt.fromBase64(signed.psbt);
        if (signed.complete) {
            this.show_flash('Fully Signed', 'green');
        } else {
            this.show_flash('Partial Signed', 'red');
        }
        return as_psbt;
    }
    async finalize_psbt(psbt: string) {
        let hex: string;
        const command = [{ method: 'finalizepsbt', parameters: [psbt] }];
        const result = (await window.electron.bitcoin_command(command))[0];
        if (
            (!result.hex && result.complete) ||
            (result.hex && !result.complete)
        ) {
            this.show_flash('PSBT Signing Error :(', 'red');
            return;
        }
        if (result.complete) {
            hex = result.hex;
        } else {
            const new_psbt = result.psbt ?? psbt;
            const sapio_finalized = await window.electron.sapio.psbt.finalize(
                new_psbt
            );
            if ('err' in sapio_finalized) {
                this.show_flash('PSBT Signing Error :(', 'red');
                return;
            }
            const sapio_result:
                | { completed: true; hex: string }
                | {
                      completed: false;
                      psbt: string;
                      error: string;
                      errors: string[];
                  } = JSON.parse(sapio_finalized.ok);
            if (sapio_result.completed) {
                hex = sapio_result.hex;
            } else {
                this.show_flash('PSBT Not Complete', 'red');
                return;
            }
        }
        try {
            const hex_tx = Bitcoin.Transaction.fromHex(hex);
            const send = [{ method: 'sendrawtransaction', parameters: [hex] }];

            const sent = (await window.electron.bitcoin_command(send))[0];
            if (sent !== hex_tx.getId()) {
                this.show_flash(
                    <div>
                        Relay Error{' '}
                        <span className="glyphicon glyphicon-question-sign"></span>
                    </div>,
                    'red',
                    () => alert(sent.message.toString())
                );
            } else {
                this.show_flash('Transaction Relayed!', 'green');
            }
        } catch (e: any) {
            this.show_flash(
                <div>
                    PSBT Error{' '}
                    <span className="glyphicon glyphicon-question-sign"></span>
                </div>,
                'red',
                () => alert(e.toString())
            );
        }
    }

    async save_psbt(psbt: string) {
        // no await
        window.electron.save_psbt(psbt);
    }
}
export function PSBTDetail(props: IProps) {
    const psbt_selection_form = React.useRef<HTMLSelectElement>(null);
    const [psbt, setPSBT] = React.useState<Bitcoin.Psbt>(props.psbts[0]!);
    const [flash, setFlash] = React.useState<JSX.Element | null>(null);
    if (props.psbts.length === 0) return null;
    function show_flash(
        msg: string | JSX.Element,
        color: string,
        onclick?: () => void
    ) {
        const click = onclick ?? (() => null);
        const elt = (
            <h3 style={{ color: color }} onClick={click}>
                {msg}
            </h3>
        );
        setFlash(elt);
        setTimeout(() => setFlash(<div></div>), 2000);
    }
    const psbt_handler = new PSBTHandler(show_flash);

    const selectable_psbts = props.psbts.map((w, i) => (
        <MenuItem key={i} value={i}>
            {i} -- {w.toBase64().substr(0, 16)}...
        </MenuItem>
    ));
    const [idx, set_idx] = React.useState(0);
    React.useEffect(() => {
        if (idx < props.psbts.length && idx >= 0) {
            setPSBT(props.psbts[idx]!);
        }
    }, [idx, props.psbts]);
    // missing horizontal
    return (
        <div className="PSBTDetail">
            <InputLabel id="label-select-psbt">PSBT Selection</InputLabel>
            <Select
                labelId="label-select-psbt"
                label="PSBT Selection"
                variant="outlined"
                ref={psbt_selection_form}
                onChange={() => {
                    const idx: number =
                        parseInt(psbt_selection_form.current?.value ?? '0') ??
                        0;
                    set_idx(idx);
                }}
            >
                {selectable_psbts}
            </Select>
            {flash}
            <Hex
                className="txhex"
                value={psbt.toBase64()}
                label="Selected PSBT"
            ></Hex>
            <div className="PSBTActions">
                <Tooltip title="Save PSBT to Disk">
                    <IconButton
                        aria-label="save-psbt-disk"
                        onClick={() => psbt_handler.save_psbt(psbt.toBase64())}
                    >
                        <SaveIcon style={{ color: red[500] }} />
                    </IconButton>
                </Tooltip>
                <Tooltip title="Sign PSBT using Node">
                    <IconButton
                        aria-label="sign-psbt-node"
                        onClick={async () => {
                            const new_psbt = await psbt_handler.sign_psbt(
                                psbt.toBase64()
                            );
                            // TODO: Confirm this saves to model?
                            psbt.combine(new_psbt);
                            setPSBT(psbt);
                        }}
                    >
                        <VpnKeyIcon style={{ color: yellow[500] }} />
                    </IconButton>
                </Tooltip>
                <Tooltip title="Combine PSBT from File">
                    <IconButton
                        aria-label="combine-psbt-file"
                        onClick={async () => {
                            // TODO: Confirm this saves to model?
                            await psbt_handler.combine_psbt(psbt);
                            setPSBT(psbt);
                        }}
                    >
                        <MergeTypeIcon style={{ color: purple[500] }} />
                    </IconButton>
                </Tooltip>
                <Tooltip title="Finalize and Broadcast PSBT with Node">
                    <IconButton
                        aria-label="combine-psbt-file"
                        onClick={async () => {
                            await psbt_handler.finalize_psbt(psbt.toBase64());
                            setPSBT(psbt);
                        }}
                    >
                        <SendIcon style={{ color: orange[500] }} />
                    </IconButton>
                </Tooltip>
                <div></div>
            </div>
        </div>
    );
}