/**
 * 
 */


import React, { useEffect, useState, Fragment, useContext } from "react";


import { Link, useParams } from 'react-router-dom';

import { SettingOutlined, PlayCircleOutlined } from '@ant-design/icons'

import { Button, Skeleton, Typography } from 'antd';

import { Forms, Columns, Scripts, Process, ProcessTransactions, StepTransactions, Pages, Menus } from './../../../../models/';

import { ExecuteScript } from "../../../../utils/script.utils";

import FormCreator from "../../../forms/components/form-creator/form-creator";

import { Location } from "../../../../utils/location/location.utils";

import { GlobalContext } from './../../../../Store';

import './task-form.scss';

import DateUtils from "../../../../utils/date/date.utils";

import * as Utils from './../../../../utils/'


const { Title } = Typography
// 
/**
 * Generic Form
 * 
 * @returns 
 */
export default function TaskForm({ record_id, step, callback = () => {

} }) {

    let params = useParams();

    const { CustomModels, user } = useContext(GlobalContext);

    let process_transaction_id = null;

    // This is when it is used inside process dashboard
    // This component can also be individually used to complete any process
    if (step.process_transaction) {

        process_transaction_id = step.process_transaction.id;

    } else {

        process_transaction_id = Location.search().process_transaction_id;

    }

    // let businessModels = require('../');

    let baseModels = require('../../../../../lib/models/')

    let models = {
        ...baseModels,
        ...CustomModels
        // ...businessModels
    }

    // Get the firestore app
    const app = Process.getFireStoreApp();


    let model = models[step.model_identifier];

    let submitModel = models[step.submit_model_identifier];

    const [form, setForm] = useState({});

    const [script, setScript] = useState('');

    const [prescript, setPrescript] = useState('');

    const [loading, setLoading] = useState(true);

    const [config, setConfig] = useState({});

    const [fields, setFields] = useState([]);

    const [menu, setMenu] = useState({});

    useEffect(() => {

        if (step.page_id) {

            loadPage(step);

        } else if (step.form_id) {

            loadForm(step).then(() => {

                loadColumns(step);

            })
        }

        return () => {

        }
    }, [])

    /**
     * Load the form 
     * 
     * @param {*} step 
     * @returns 
     */
    function loadForm(step) {

        return Forms.getRecord(step.form_id).then((result) => {

            setForm(result);

            // load Scripts on submit
            result.on_submit_script_id && loadScript(result.on_submit_script_id);


            // load Scripts on submit
            result.before_submit_script_id && loadPreScript(result.before_submit_script_id);

        })
    }

    /**
     * 
     * 
     * @param {*} step 
     */
    function loadPage(step) {

        let menus = null;

        Pages.getRecord(step.page_id).then((result) => {

            var queries = [{
                field: 'page_id',
                value: step.page_id
            }]

            Menus.get(queries).then(({ menus }) => {

                if (menus.length) {

                    menus = menus[0];
                }

                let menu = {
                    step,
                    page: result,
                    ...menus
                }

                setMenu(menu);

                setLoading(false);
            })
        })
    }

    /**
     * Load columns of the form
     * 
     * @param {*} step 
     */
    const loadColumns = (step) => {

        var queries = [{
            field: 'form_id',
            value: step.form_id,
        }]

        Columns.getColumns(queries).then((result) => {

            setFields(result);

            setConfig({
                fields: result
            })

            setLoading(false);
        })
    }

    /**
     * Load the Script statement
     * 
     * @param {*} script_id 
     */
    const loadScript = (script_id) => {

        Scripts.getRecord(script_id).then((result) => {

            setScript(result.value);

        })
    }

    /**
     * Load the Script statement
     * 
     * @param {*} script_id 
     */
    const loadPreScript = (script_id) => {

        Scripts.getRecord(script_id).then((result) => {

            setPrescript(result.value);

        })
    }

    /**
     * On Submit of Task 
     * 
     * @param {*} values 
     */
    async function onSubmit(values) {

        // Starting a batched write
        let batch = app.batch();

        return new Promise(async (resolve) => {

            // Submit the model , First level of submission
            // Instead of submitting to a model 
            // We have to update to the route 
            // If the route is passed
            console.log("Submission of form Started");

            // Before Submit of form , execute the script
            values = await executeScript(values, null, prescript);

            let modelRef = {};

            if (submitModel) {

                // Get the model reference to start with write
                modelRef = submitModel.getRecordReference();

                // Update the reference with values
                const result = await batch.set(modelRef, model.appendDefaultValues(values));
            }

            console.log("Submission of form Completed");

            // console.log(result);

            console.log("Script execution started");

            // On Submit of form , execute the script
            await executeScript(values, { id: modelRef.id }, script);

            console.log("Script execution ended");

            // const result = await Process.onStepCompletion({ batch, process_transaction_id, step });

            // The first Step transaction
            let step_transaction = step.step_transactions[0];

            // We have to forward the process transaction to the next sub process 
            // 
            // await triggerSubProcess(step, process_transaction_id)

            // console.log("Triggering Subprocesses", step.trigger_sub_process_ids.map((record) => record.id));

            // Trigger the sub process
            if (step.trigger_sub_process_ids && step.trigger_sub_process_ids.length)

                await Promise.all(step.trigger_sub_process_ids.map(async (step_id) => {

                    let params = {
                        step_id: step_id
                    }

                    console.log("Updating Process Transaction started", process_transaction_id);

                    // Reference for process transaction
                    var processTransactionReference = ProcessTransactions.getRecordReference(process_transaction_id)

                    console.log(`Got process transaction`, processTransactionReference);

                    // Move the process transaction to next step
                    // await batch.update(processTransactionReference, model.appendDefaultValues(params));
                    await batch.set(processTransactionReference, model.appendDefaultValues(params));

                    console.log("Updating Process Transaction ended");

                    // If there is a step transaction record , 
                    // We have to update that its completed

                    // We have to record a step transaction record for every event
                    let body = {
                        step_id: step_id,
                        process_id: step.process_id,
                        process_transaction_id: process_transaction_id,
                        record_id: record_id,
                        start_time: new Date()
                    }

                    // Record the Step Transaction
                    var stepTransactionReference = StepTransactions.getRecordReference()

                    console.log("Step Transaction Add started");

                    return await batch.set(stepTransactionReference, model.appendDefaultValues(body));

                    console.log("Step Transaction Add Completed");

                }));

            // console.log("Triggering Process started", step.trigger_process_ids.map((record) => record.id));

            if (step.trigger_process_ids && step.trigger_process_ids.length)

                // We also have to trigger any process that this step would trigger
                await Promise.all(step.trigger_process_ids.map((process_id) => {

                    let body = {
                        record_id: record_id,
                        model_identifier: 'Candidates'
                    }

                    console.log("Trigger Process Started");

                    return Process.triggerProcessBatch(batch, process_id, body, process_transaction_id).catch((error) => {

                        console.log(error, "Trigger process failed");
                    })

                }));

            console.log("Step Transaction Update Started");

            if (step_transaction) {

                console.log("Found Step Transaction to Update");

                // We have to record a step transaction record for every event
                let body = {
                    end_time: new Date(),
                    // end_time: DateUtils.getTime(),
                    completed: true,
                }

                // Record the Step Transaction
                let stepTransactionReference = StepTransactions.getRecordReference(step_transaction.id);

                await batch.update(stepTransactionReference, model.appendDefaultValues(body));

                console.log("Step Transaction Update Completed");

                // Commit the batch
                batch.commit().then(() => {

                    console.log("Commit of records completed");

                    callback();
                });

            } else {

                // Commit the batch
                batch.commit().then(() => {

                    console.log("Commit of records completed");

                    callback();

                });
            }
        })
    }


    /**
     * Trigger the Sub Process
     * 
     * @param {*} step 
     * @param {*} process_transaction_id 
     * @returns 
     */
    async function triggerSubProcess(step, process_transaction_id) {

        if (step.trigger_sub_process_ids.length) {

            return step.trigger_sub_process_ids.map((step_id) => {

                let params = {

                    step_id: step_id
                }

                return ProcessTransactions.update(process_transaction_id, params)
            });

        } else {

            return new Promise(function (resolve, reject) {
                resolve('start of new Promise');
            });

        }
    }

    /**
     * 
     * 
     * @param {*} values 
     * @returns 
     */
    async function executeScript(values, response, script) {

        var scripts = [];

        if (script) {
            scripts.push(script);
        }

        if (script) {

            return await ExecuteScript({
                formContent: values,
                scripts,
                context: {
                    ...models,
                    ...Utils,
                    params
                },
                contextName: 'models',
                executionType: '',
                response
            });

        } else {

            return new Promise(function (resolve, reject) {
                resolve('start of new Promise');
            });
        }
    }



    return (<div className="task-form">

        {
            loading
                ?
                <Skeleton />
                :
                <>


                    {/* 
                    
                    A Task can be completed either with a form or with a checklist
                    or with a custom page , in case of which we redirect the user to that particular page 
                    On completion of the step , we update the status of the record
                    
                    */}

                    {
                        menu.id
                            ?
                            <>

                                <p>
                                    {menu.step && menu.step.description}
                                </p>

                                <Link to={`${menu.path.replace(':id', record_id)}?process_transaction_id=${process_transaction_id}`} className={'configure-button'}>
                                    <Button size={'small'}>
                                        <PlayCircleOutlined />
                                        Go to Menu
                                    </Button>
                                </Link>

                            </>
                            :
                            <>

                                <Title level={4}>Task Form</Title>

                                <p>
                                    To complete this step , Please fill the below form .
                                </p>

                                {/* Form Creator */}
                                <FormCreator
                                    onSubmit={onSubmit}
                                    model={config}
                                    config={{
                                        fields
                                    }}
                                    fields={fields}
                                />

                                <div className="form-footer">

                                    {
                                        user.isAdmin
                                        &&
                                        <Link to={`/forms/${form.id}`} className={'configure-button'}>
                                            <Button size={'small'}>
                                                <SettingOutlined />
                                                Configure
                                            </Button>
                                        </Link>
                                    }

                                </div>
                            </>
                    }
                </>
        }

    </div>)
}