import React, { useCallback, useContext, useEffect, useState } from 'react';
import { ClientContext } from '../../contexts/clientProvider';
import { InfinityMintScriptArguments } from 'infinitymint/dist/app/interfaces';
import Loading from '../bootstrap/Loading';
import { load } from '../../main';
import { Alert, Button, Card, Col, Container, Row } from 'react-bootstrap';
import { log } from '../../utils/helpers';

export default function Execute({
    script,
    args = [],
}: {
    script: string;
    args?: InfinityMintScriptArguments[];
}) {
    const [loading, setLoading] = useState(false);
    const [connected, setConnected] = useState(false);
    const client = useContext(ClientContext);
    const [socket, setSocket] = useState<WebSocket>(null);
    const [running, setRunning] = useState(false);
    const createWebsocket = useCallback(async () => {
        if (!client.loaded || !script) return;
        try {
            setLoading(true);
            let newSocket = new WebSocket(
                client.controller.config?.api?.webSocket ||
                    'ws://localhost:8080'
            );

            newSocket.onmessage = (event) => {
                console.log(event.data);
                let consoleHandle = document.getElementById('console');
                let data = JSON.parse(event.data);

                data.forEach((item) => {
                    consoleHandle.innerHTML += item + '<br/>';
                });

                //scroll to bottom
                consoleHandle.scrollTop = consoleHandle.scrollHeight;
            };
            newSocket.onopen = () => {
                setConnected(true);
                setSocket(newSocket);
                log('Connected to InfinityMint WebSocket');
            };
        } catch (error) {
            console.error(error);
            setConnected(false);
        } finally {
            setLoading(false);
        }
    }, [client, script]);

    const runScript = useCallback(async () => {
        if (!socket) return;

        try {
            let consoleHandle = document.getElementById('console');

            consoleHandle.innerHTML =
                'Running Script: <b style="color: cyan">' +
                script +
                '</b>...<br/>';

            let newArgs = {};
            args.forEach((arg) => {
                newArgs[arg.name] = arg;

                if (arg.type === 'boolean')
                    newArgs[arg.name].value =
                        arg.value === 'true' || arg.value === true;

                if (arg.type === 'number')
                    newArgs[arg.name].value = parseInt(arg.value);
            });

            setTimeout(() => {
                consoleHandle.innerHTML = '';
                let data = {
                    command: script,
                    args: newArgs,
                };
                socket.send(JSON.stringify(data));
            }, 1000);
        } catch (error) {}
    }, [socket, script, args]);

    useEffect(() => {
        let main = async () => {
            await createWebsocket();
        };
        main();
    }, [createWebsocket]);

    useEffect(() => {
        return () => {
            if (socket) socket.close();
        };
    }, [socket]);

    return (
        <Container fluid>
            {!client.loaded || loading ? (
                <>
                    <Loading />
                </>
            ) : (
                <>
                    {!connected ? (
                        <Row>
                            <Col>
                                <Alert variant="danger">
                                    <Alert.Heading>
                                        Error connecting to InfinityMint
                                    </Alert.Heading>
                                    <p>
                                        Please check if InfinityMint is running
                                        and try again.
                                    </p>
                                </Alert>
                            </Col>
                        </Row>
                    ) : (
                        <>
                            <Card>
                                <Card.Header>
                                    Executing Script{' '}
                                    <span className="badge bg-secondary">
                                        {script}
                                    </span>
                                </Card.Header>
                                <Card.Body>
                                    <div
                                        id="console"
                                        style={{
                                            height: '50vh',
                                            overflow: 'auto',
                                            backgroundColor: '#000',
                                            color: '#fff',
                                            fontFamily: 'monospace',
                                            fontSize: '12px',
                                            padding: '12px',
                                            border: '2px solid gray',
                                        }}
                                    >
                                        Click{' '}
                                        <b
                                            style={{
                                                color: 'green',
                                            }}
                                        >
                                            Run
                                        </b>{' '}
                                        to start the execution...
                                        <br />
                                        <br />
                                        <b
                                            style={{
                                                color: 'magenta',
                                            }}
                                        >
                                            Arguments [{args?.length || 0}]
                                        </b>
                                        {args && args.length !== 0
                                            ? args.map((arg) => (
                                                  <>
                                                      <br />
                                                      {arg.name} {'=>'}{' '}
                                                      {arg.value === undefined
                                                          ? 'undefined'
                                                          : arg.value.toString()}
                                                  </>
                                              ))
                                            : ' => no arguments'}
                                    </div>
                                    {!running ? (
                                        <div className="d-grid mt-2">
                                            <Button
                                                variant="success"
                                                onClick={(e) => {
                                                    setRunning(true);
                                                    runScript();
                                                }}
                                            >
                                                Run
                                            </Button>
                                        </div>
                                    ) : null}
                                </Card.Body>
                            </Card>
                        </>
                    )}
                </>
            )}
        </Container>
    );
}
