import React, { useState, useEffect, useCallback } from 'react';
import { Table, Button, Space, Typography } from 'antd';
import { useSelector, useDispatch } from 'react-redux';
import * as Antd from 'antd'
import * as Loader from './loader'
import * as Common from './common'

import {
    CheckCircleOutlined,
    ClockCircleOutlined,
    ExclamationCircleOutlined,
    LoadingOutlined,
} from '@ant-design/icons';

import * as Shared from 'placeholder-shared'
const layout = {
    labelCol: { span: 5 },
    wrapperCol: { span: 16 },
};
const tailLayout = {
    wrapperCol: { offset: 5, span: 16 },
};

enum RunState {
    running, waiting, error
}
export const JobResults = (props: {}) => {
    const [runState, setRunState] = useState(RunState.waiting)
    const [error, setError] = useState(null);
    const dispatch = useDispatch()
    const jobResults = useSelector(state => (state as any).jobResults)

    const getStatus = (jobStatus) => {
        switch (jobStatus) {
            case 'pending':
                return <Antd.Tag icon={<ClockCircleOutlined />} color="processing">pending</Antd.Tag>
                break
            case 'success':
                return <Antd.Tag icon={<CheckCircleOutlined />} color="success">success</Antd.Tag>
                break
            case 'failure':
                return <Antd.Tag icon={<ExclamationCircleOutlined />} color="error">failure</Antd.Tag>
                break
            default:
                console.error("Unknown JobStatus in JobResults");
                console.assert(false);
        }
    }

    const handleResults = (err, data) => {
        if (err) {
            console.error("error", error)
            setError(err)
            setRunState(RunState.error)// ant
        } else {
            const jobResults = data.Items.map((o, i) => {
                const jobResult = {
                    key: i,
                    StartTime: <TimeString isoString={o.CreationDate} />,
                    JobId: <Antd.Typography.Text strong>{'#' + o.JobResultId}</Antd.Typography.Text>,
                    JobDuration: <span>{parseInt(o.JobDuration)/1000}s</span>,
                    Status: getStatus(o.JobStatus),
                    JobDetail: <DetailCell jobStatus={o.JobStatus} jobData={o.JobData} />,
                    JobData: o.JobData,
                    JobStatus: o.JobStatus
                }
                return jobResult;
            });
            dispatch(Shared.State.getJobResultsAction(jobResults))
            setRunState(RunState.waiting)
        }
    }

    const refreshJobs = useCallback(() => {
        setError(null)
        setRunState(RunState.running)
        Shared.Common.getDynamoClient()
            .then(({ docClient, targetUserId }) => {
                Shared.Dynamo.queryJobResult(docClient, targetUserId, (err, data) => {
                    handleResults(err, data);
                })
            })
    }, [setRunState, setError])
    useEffect(() => {
        refreshJobs()
    }, [refreshJobs])
    const columns = [
        {
            title: 'JobId',
            dataIndex: 'JobId',
            key: 'JobId',
        },
        {
            title: 'StartTime',
            dataIndex: 'StartTime',
            key: 'StartTime',
        },
        {
            title: 'Duration',
            dataIndex: 'JobDuration',
            key: 'JobDuration',
        },
        {
            title: 'Status',
            dataIndex: 'Status',
            key: 'Status',
        },
        {
            title: 'JobDetail',
            dataIndex: 'JobDetail',
            key: 'JobDetail',
        }
    ];
    const getChildren = () => {
        if (runState == RunState.error) {
            return <Antd.Alert type='error' message="Unable to Fetch Job Results" />
        }
        else if (runState == RunState.running) {
            return <LoadingOutlined style={{ fontSize: '50px' }} />
        }
        else {
            return <Table className='JobResultsTable columnFlexBox flexGrow'
                columns={columns}
                expandedRowRender={(record, index, indent, expanded) => {
                    return <ModelTable jobStatus={record.JobStatus} jobData={record.JobData} />
                }
                }
                dataSource={jobResults}
                pagination={{ pageSize: 5 }}
                scroll={{ y: '100%' }}
                footer={() => <Common.DivWithClassName className='rowFlexBox'>
                    <Common.DivWithClassName className='floatRight'>
                        <Antd.Button onClick={refreshJobs}>Refresh</Antd.Button>
                    </Common.DivWithClassName>
                </Common.DivWithClassName>}
            />
        }
    }


    return <Common.DivWithClassName className='columnFlexBox flexGrow'>
        {getChildren()}
    </Common.DivWithClassName>
}

const TimeString = (props: { isoString: string; }): any => {
    const { isoString } = props;
    const time = new Date(isoString).toLocaleString().split(' ');    
    return <div><Antd.Typography.Text code>{time[0]}</Antd.Typography.Text><br /><Antd.Typography.Text code>{time[1]}</Antd.Typography.Text></div>
}

const DetailCell = (props: { jobStatus: string; jobData: any }): any => {
    const { jobData, jobStatus } = props;

    const getDetail = (jobData) => {
        let counter = (() => {
            let successes = 0;
            let failures = 0;
            const increment = (successBoo) => {
                if (successBoo) {
                    successes++
                } else {
                    failures++
                }
            }
            return {
                increment: increment,
                getSuccesses: () => successes,
                getFailures: () => failures
            };
        })();
        if (jobData) {
            Shared.TreeData.forEachRunResultInTask(jobData.treeData[1], jobData.steps, jobData.runResults, (runResult, stepCounter) => {
                if(runResult.createResult.hasOwnProperty('success')){
                    counter.increment(runResult.createResult.success)
                }   
            })
            return <span>Successes: {counter.getSuccesses()}, Failures: {counter.getFailures()}</span>;
        } else {
            return null
        }
    }
    switch (jobStatus) {
        case 'pending':
            return <p>'Job is still pending'</p>
            break;
        case 'failure':
            if (jobData && jobData.treeData) {
                return <p>{getDetail(jobData)}</p>
            } else if (jobData) {
                return <p>{JSON.stringify(jobData).substring(0, 32)}</p>
            } else {
                return <p>'unknown error'</p>
            }
            break;
        case 'success':
            return <p>{getDetail(jobData)}</p>
            break;
        default:
            console.assert(false)

    }
    return null;
}

const ModelTable = (props: { jobStatus: string; jobData }): any => {
    const { jobData, jobStatus } = props;
    let models = [];
    if (jobStatus == 'pending' || (jobStatus == 'failure') && !jobData) {
        return null;
    }
    const getStatusString = (boo) => {
        if (boo) {
            return <Antd.Tag icon={<CheckCircleOutlined />} color="success">success</Antd.Tag>
        } else {
            return <Antd.Tag icon={<ExclamationCircleOutlined />} color="error">failure</Antd.Tag>
        }
    }
    const modelColumns = [
        {
            title: 'Model',
            dataIndex: 'ModelName',
            key: 'ModelName',
        },
        {
            title: 'StartTime',
            dataIndex: 'ModelStartTime',
            key: 'ModelStartTime',
        },
        {
            title: 'Duration',
            dataIndex: 'ModelDuration',
            key: 'ModelDuration',
        },
        {
            title: 'Status',
            dataIndex: 'ModelStatus',
            key: 'ModelStatus',
        }
    ];
    Shared.TreeData.forEachRunResultInTask(jobData.treeData[1], jobData.steps, jobData.runResults, (runResult, stepCounter) => {
        const modelDuration = (runResult.startTime && runResult.endTime) ? Shared.Common.measureSeconds(runResult.startTime, runResult.endTime)/1000+'s' : 'not calculated';
        const modelStartTime = (runResult.startTime) ? <TimeString isoString={runResult.startTime} /> : 'not found';
        models.push({
            key: stepCounter,
            ModelName: <Antd.Typography.Text>{Shared.Runner.getName(jobData.steps[stepCounter])}</Antd.Typography.Text>,
            ModelStartTime: modelStartTime,
            ModelDuration: modelDuration,
            ModelStatus: (runResult.createResult.hasOwnProperty('success')) ? getStatusString(runResult.createResult.success) : 'no status',
        })
    })
    
    return (
        <Table dataSource={models} columns={modelColumns} size="small" pagination={false} />
    )
}
