import styles from './styles.module.css'
import {useEffect, useState} from "react"
import DeleteForeverOutlined from "@mui/icons-material/DeleteForeverOutlined"
import StopCircleOutlined from "@mui/icons-material/StopCircleOutlined"
import PauseCircleOutline from "@mui/icons-material/PauseCircleOutline"
import PlayCircleOutline from "@mui/icons-material/PlayCircleOutline"
import HourglassEmptyOutlined from "@mui/icons-material/HourglassEmptyOutlined"
import CheckCircleOutline from "@mui/icons-material/CheckCircleOutline"
import ErrorOutline from "@mui/icons-material/ErrorOutline"
import ReplayOutlined from "@mui/icons-material/ReplayOutlined"
import RunCircleOutlined from "@mui/icons-material/RunCircleOutlined"
import FactCheckOutlined from "@mui/icons-material/FactCheckOutlined"
import {
    Box,
    TextField,
    CircularProgress,
    IconButton,
    LinearProgress,
    TableContainer,
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableRow,
    TablePagination, Autocomplete
} from "@mui/material"
import ConfirmDialog from "../confirm-dialog";
import {ProcessInterface, Status} from "../../../api/sm/responses/processes";
import Command from "../commands/elements/command";
import {CommandInterface} from "../../../api/sm/responses/comamnds";
import Grid from '@mui/material/Grid';
import {useApi} from "../../../hooks/use-api";

enum Action {
    Run,
    Repeat,
    Stop,
    Kill,
    Play,
    Pause,
}

export default function Processes() {
    const [processes, setProcesses] = useState<ProcessInterface[]>([]);
    const [commands, setCommands] = useState<CommandInterface[]>([]);
    const [page, setPage] = useState<number>(0);
    const [count, setCount] = useState<number>(0);
    const [type, setType] = useState<string | null>('');
    const [name, setName] = useState<string | null>('');
    const [loading, setLoading] = useState<boolean>(true);
    const [modalLoading, setModalLoading] = useState<boolean>(true);
    const [action, setAction] = useState<Action | null>(null);
    const [command, setCommand] = useState<CommandInterface | null>(null);
    const [selectedProcess, setSelectedProcess] = useState<ProcessInterface | null>(null);
    const [optionList, setOptionList] = useState<Record<string, any>>({});
    const [argumentList, setArgumentList] = useState<Record<string, any>>({});
    const api = useApi()

    let variants = commands.map((command: CommandInterface, index: number) => command.name);

    let refreshCommands = async () => {
        const { data: commands } = await api.useMemory().getCommands()
        setCommands(commands)
    }

    useEffect(() => {
        refreshCommands()
    }, [])

    let refreshLock = false
    let refreshProcesses = async () => {
        if (refreshLock) {
            return
        }
        refreshLock = true

        let data: any = {}
        if (type && type !== 'None') {
            data['type'] = type.toLowerCase()
        }
        if (!!name) {
            data['name'] = name
        }
        const { data: processes, headers } = await api.getProcesses({
            ...data,
            page: page + 1,
            limit: 20,
        })
        setProcesses(processes)
        setCount(Number(headers.get('X-Pagination-Count')))
        setLoading(false)
        refreshLock = false
    }
    let output = async (process: ProcessInterface) => {
        const { data: output } = await api.getProcessOutput({
            id: process.id
        })

        let a = document.createElement("a");
        let file = new Blob([output], {type: 'plain/text'});
        a.href = URL.createObjectURL(file);
        a.download = `${process.id}.txt`;
        a.click();
    }

    useEffect(() => {
        const timer = setInterval(() => refreshProcesses(), 1000)
        return () => clearInterval(timer);
    }, [page, name, type]);

    useEffect(() => {
        if (action === null) {
            setSelectedProcess(null)
            setCommand(null)
        }
    }, [action]);

    let isFinished = (process: ProcessInterface) => process.cancelledAt || process.completedAt

    const handleChangePage = (event: any, page: number) => {
        setPage(page);
    }

    const openDialog = (process: ProcessInterface, action: Action) => {
        setSelectedProcess(process)
        setAction(action)
    }

    let lock = false
    const agreeCallback = async (dialogId: string) => {
        if (lock) {
            return
        }
        if (!selectedProcess) {
            return
        }
        lock = true

        if (action === Action.Run) {
            await api.runCommand({
                commandName: selectedProcess.name,
                options: optionList,
                arguments: argumentList,
                requestId: dialogId,
            })
        }

        if (action === Action.Repeat) {
            await api.repeatProcess({
                id: selectedProcess.id,
                requestId: dialogId
            })
        }

        lock = false
        setAction(null)
    }

    let callback = (name: string, optionList: Record<string, any>, argumentList: Record<string, any>) => {
        setOptionList(optionList)
        setArgumentList(argumentList)
    }

    if (loading) {
        return (
            <Box sx={{ display: 'flex', marginTop: '200px' }}>
                <CircularProgress />
            </Box>
        );
    }

    return (
        <>
            <br/>
            <Grid container>
                <Grid item xs={1}>
                    <Autocomplete
                        value={type}
                        onChange={(event: any, newValue: string | null) => {
                            setType(newValue);
                        }}
                        disablePortal
                        options={['None', "Running", "History"]}
                        renderInput={(params) => <TextField {...params} label="Type"/>}
                    />
                </Grid>
                <Grid item xs={3}>
                    <Autocomplete
                        sx={{marginLeft: 5}}
                        value={name}
                        onChange={(event: any, newValue: string | null) => {
                            setName(newValue || '');
                        }}
                        disablePortal
                        options={variants}
                        renderInput={(params) => <TextField {...params} label="Commands"/>}
                    />
                </Grid>
            </Grid>
            <TableContainer>
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Name</TableCell>
                            <TableCell>Progress</TableCell>
                            <TableCell>Status</TableCell>
                            <TableCell>Action</TableCell>
                            <TableCell>Created</TableCell>
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {processes.map((process: ProcessInterface, index: number) => (
                            <TableRow key={process.id}>
                                <TableCell>{process.name}</TableCell>
                                <TableCell>
                                    {!process.progress && !isFinished(process) && <LinearProgress/>}
                                    {!process.progress && isFinished(process) && <LinearProgress variant="determinate" value={100}/>}
                                    {process.progress && <LinearProgress variant="determinate" value={process.progress.percent}/>}
                                    {process.progress && <span>
                                    {`${process.progress.progress}`} / {`${process.progress.total}`} - {process.progress.percent}% [{process.progress.memory}] / {process.progress.remaining}
                                </span>}
                                    {process.canPlay && <IconButton onClick={() => openDialog(process, Action.Play)} title={`Play`} aria-label="Play">
                                        <PlayCircleOutline/>
                                    </IconButton>}
                                    {process.canPause && <IconButton onClick={() => openDialog(process, Action.Pause)} title={`Pause`} aria-label="Pause">
                                        <PauseCircleOutline/>
                                    </IconButton>}
                                    {process.canStop && <IconButton onClick={() => openDialog(process, Action.Stop)} title={`Stop`} aria-label="Stop">
                                        <StopCircleOutlined/>
                                    </IconButton>}
                                </TableCell>
                                <TableCell>
                                    {Status.Error === process.status && <IconButton title={`Error`} aria-label="Error">
                                        <ErrorOutline/>
                                    </IconButton>}
                                    {Status.Success === process.status && <IconButton title={`Success`} aria-label="Success">
                                        <CheckCircleOutline/>
                                    </IconButton>}
                                    {Status.Running === process.status && <IconButton title={`Running`} aria-label="Running">
                                        <RunCircleOutlined/>
                                    </IconButton>}
                                    {Status.Cancelled === process.status && <IconButton title={`Cancelled`} aria-label="Cancelled">
                                        <StopCircleOutlined/>
                                    </IconButton>}
                                    {Status.Wait === process.status && <IconButton title={`Wait`} aria-label="Wait">
                                        <HourglassEmptyOutlined/>
                                    </IconButton>}
                                </TableCell>
                                <TableCell>
                                    {process.canRepeat && <IconButton onClick={() => openDialog(process, Action.Repeat)} title={`Repeat`} aria-label="Repeat">
                                        <ReplayOutlined/>
                                    </IconButton>}
                                    {process.canKill && <IconButton onClick={() => openDialog(process, Action.Kill)} title={`Kill`} aria-label="Kill">
                                        <DeleteForeverOutlined/>
                                    </IconButton>}
                                    {process?.outputId && <IconButton title={`Output`} onClick={() => output(process)} aria-label="Output">
                                        <FactCheckOutlined/>
                                    </IconButton>}
                                </TableCell>
                                <TableCell title={new Date(process.createdAt).toLocaleString()}>
                                    {new Date(process.createdAt).toLocaleDateString()}
                                </TableCell>
                            </TableRow>
                        ))}
                    </TableBody>
                </Table>
            </TableContainer>
            <TablePagination
                component="div"
                count={count}
                rowsPerPage={20}
                page={page}
                onPageChange={handleChangePage}
            />
            {selectedProcess && <ConfirmDialog
                title={selectedProcess.name}
                open={Action.Repeat === action}
                agreeCallback={agreeCallback}
                modifyCallback={async () => {
                    setAction(Action.Run)
                    setModalLoading(true)
                    let {data: command} = await api.getCommand(selectedProcess.name)
                    setCommand(command)
                    setModalLoading(false)
                }}
                closeCallback={() => {setAction(null)}}>
                Reply?
            </ConfirmDialog>}
            {selectedProcess && <ConfirmDialog
                title={selectedProcess.name}
                open={Action.Run === action}
                agreeCallback={agreeCallback}
                closeCallback={() => {setAction(null)}}>
                {modalLoading && <Box sx={{ display: 'flex' }}>
                    <CircularProgress />
                </Box>}
                {!modalLoading && !!command && (Action.Run === action) && <Command
                    command={command}
                    optionsParams={selectedProcess.options}
                    argumentsParams={selectedProcess.arguments}
                    callback={callback}/>}
            </ConfirmDialog>}
            {selectedProcess && <ConfirmDialog
                title={`Are you sure?`}
                open={ !!action && ([Action.Play, Action.Pause, Action.Stop, Action.Kill].indexOf(action) > -1) }
                agreeCallback={async () => {
                    Action.Play === action && await api.playProcess(selectedProcess.id)
                    Action.Pause === action && await api.pauseProcess(selectedProcess.id)
                    Action.Stop === action && await api.stopProcess(selectedProcess.id)
                    Action.Kill === action && await api.killProcess(selectedProcess.id)
                    setAction(null)
                }}
                closeCallback={() => {setAction(null)}}>
                {selectedProcess.name}
            </ConfirmDialog>}
        </>
    )
}
