import React, { useState, useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { useNavigate, useParams } from 'react-router-dom';
import { klona } from 'klona';
import { head, isNil, isEmpty, pathOr } from 'ramda';
import { useForm } from 'react-hook-form';
import 'quill/dist/quill.core.css';
import { evaluate } from 'mathjs';
import equal from 'fast-deep-equal';

// store
import { storeSet, useStoreValue } from '../../store';

// api
import FormsService from '../../service/forms-service';

// components
import { Skeleton } from 'primereact/skeleton';
import { Button } from 'primereact/button';
import FormField from '../../components/FormField';
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';

// tools
import {
    isCAP,
    isCodiceFiscale,
    isEmail,
    isEmailPEC,
    isIBAN,
    isMarcaDaBollo,
    isPIVA,
    isUrl, minChecks, maxChecks, nonEmptyTables
} from '../../helpers/validators';
import renderHtmlContent from '../../helpers/renderHtmlContent';
import renderWithDataVars from '../../helpers/renderWithDataVars';
import getTokens from '../../helpers/getTokens';
import parseCommaDecimal from '../../helpers/parseCommaDecimal';

const BandoFormsPreview = () => {
    const { id, formId } = useParams();
    const navigate = useNavigate();
    const [formData, setFormData] = useState([]);
    const [formName, setFormName] = useState('');
    const isAsyncRequest = useStoreValue('isAsyncRequest');
    const {
        control,
        handleSubmit,
        formState: { errors },
        getValues,
        register,
        setValue,
        watch,
        reset
    } = useForm({ defaultValues: {}, mode: 'onChange' });
    const values = getValues();
    const formValues = watch();
    const validationFns = {
        isPIVA,
        isCodiceFiscale,
        isCAP,
        isIBAN,
        isEmail,
        isEmailPEC,
        isUrl,
        isMarcaDaBollo,
        minChecks,
        maxChecks,
        nonEmptyTables
    }

    const onSubmit = () => {
    }

    const closePreview = () => {
        const parsedId = parseInt(id)
        const bandoId = !isNaN(parsedId) ? parsedId : 0;
        const parsedFormId = parseInt(formId)
        const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;
        navigate(`/bandi/${bandoId}/forms/${bandoFormId}`);
    }

    const getFormCallback = (data) => {
        if (data.status === 'SUCCESS') {
            setFormName(data.data.label);
            const elements = klona(data.data.content);
            setFormData(elements);
        }
        storeSet('unsetAsyncRequest');
    }

    const errGetFormCallbacks = (data) => {
        set404FromErrorResponse(data);
        storeSet('unsetAsyncRequest');
    }

    useEffect(() => {
        let updatedFormValues = klona(formValues);
        let context = {};

        // eslint-disable-next-line array-callback-return
        formData.map((o) => {
            const variable = head(o.settings.filter(o => o.name === 'variable'));
            const formula = head(o.settings.filter(o => o.name === 'formula'));

            if (formula && !isEmpty(formula.value)) {
                try {
                    context = getTokens(formula.value)
                        .filter(v => !['false', 'null', 'true'].includes(v))
                        .reduce((acc, cur) => {
                            acc[cur] = isNil(context[cur]) ? 0 : parseCommaDecimal(context[cur]);
                            return acc;
                        }, context);
                } catch {
                    console.error('Error in formula', formula)
                    context = {}
                }
                const mathFormula = renderWithDataVars(formula.value, context);
                try {
                    updatedFormValues[o.id] = evaluate(mathFormula);
                } catch (e) {
                    console.log('Error in math formula: "', mathFormula, '"', e.message);
                    updatedFormValues[o.id] = 0;
                }
            }

            if (variable && !isEmpty(variable.value)) {
                context[variable.value[0]] = 'criteria_table' === o.name
                    ? pathOr(0, [o.id, 'total'], updatedFormValues)
                    : pathOr(0, [o.id], updatedFormValues);
            }
        });

        if (!isEmpty(updatedFormValues) && !equal(updatedFormValues, formValues)) {
            reset(updatedFormValues);
        }
    }, [formValues]);

    useEffect(() => {
        const parsedFormId = parseInt(formId)
        const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0;

        if (bandoFormId) {
            storeSet('setAsyncRequest');
            FormsService.getFormById(bandoFormId, getFormCallback, errGetFormCallbacks);
        }
    }, [id, formId]);

    return (
        <div className="appPage">
            {!isAsyncRequest && !isNil(formName)
                ? <div className="appPage__pageHeader">
                    <h1>{formName}</h1>
                </div>
                : <>
                    <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
                    <Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
                </>}

            <div className="appPage__spacer"></div>

            {!isAsyncRequest
                ? <div className="appPage__content">
                    <div className="appPageSection__preview">
                        <Button
                            type="button"
                            outlined
                            onClick={closePreview}
                            label={__('Chiudi Anteprima', 'gepafin')}
                            icon="pi pi-arrow-left" iconPos="left"/>
                    </div>

                    <form className="appForm" onSubmit={handleSubmit(onSubmit)}>
                        {!isNil(formName)
                            ? formData.map(o => {
                                const label = head(o.settings.filter(o => o.name === 'label'));
                                const text = head(o.settings.filter(o => o.name === 'text'));
                                const placeholder = head(o.settings.filter(o => o.name === 'placeholder'));
                                const options = head(o.settings.filter(o => o.name === 'options'));
                                let tableColumns = head(o.settings.filter(o => o.name === 'table_columns'));
                                if (!tableColumns) {
                                    tableColumns = head(o.settings.filter(o => o.name === 'criteria_table_columns'));
                                }
                                const template = head(o.settings.filter(o => o.name === 'template'));
                                const step = head(o.settings.filter(o => o.name === 'step'));
                                const mime = head(o.settings.filter(o => o.name === 'mime'));
                                const formula = head(o.settings.filter(o => o.name === 'formula'));
                                let mimeValue = '';

                                if (mime) {
                                    mimeValue = mime.value.map(o => o.code ? o.code : o.ext);
                                }

                                const validations = Object.keys(o.validators).reduce((acc, cur) => {
                                    if (o.validators[cur]) {
                                        if (['min', 'max', 'minLength', 'maxLength', 'maxSize'].includes(cur)) {
                                            acc[cur] = parseInt(o.validators[cur]);
                                        } else if ('pattern' === cur) {
                                            acc[cur] = new RegExp(o.validators[cur])
                                        } else if ('isRequired' === cur) {
                                            acc[cur] = o.validators[cur]
                                        } else if ('custom' === cur && validationFns[o.validators[cur]]) {
                                            if (!acc.validate) {
                                                acc.validate = {}
                                            }
                                            acc.validate[cur] = validationFns[o.validators[cur]]
                                        }
                                    }

                                    return acc;
                                }, {});

                                return ['paragraph'].includes(o.name) && text
                                    ? <div key={o.id}>
                                        <div className="ql-editor">
                                            {renderHtmlContent(text.value)}
                                        </div>
                                    </div>
                                    : <FormField
                                        key={o.id}
                                        readOnly={formula && !isEmpty(formula.value)}
                                        type={o.name}
                                        fieldName={o.id}
                                        label={label ? label.value : ''}
                                        placeholder={placeholder ? placeholder.value : ''}
                                        control={control}
                                        register={register}
                                        errors={errors}
                                        defaultValue={values[o.id] ? values[o.id] : ''}
                                        maxFractionDigits={step ? step.value : 0}
                                        accept={mimeValue}
                                        config={validations}
                                        options={options ? options.value : []}
                                        setDataFn={setValue}
                                        sourceId={0}
                                        useGrouping={false}
                                        tableColumns={tableColumns ? tableColumns.value : {}}
                                        template={template ? template.value : null}
                                    />
                            }) : null}
                    </form>

                    <div className="appPageSection__preview">
                        <Button
                            type="button"
                            outlined
                            onClick={closePreview}
                            label={__('Chiudi Anteprima', 'gepafin')}
                            icon="pi pi-arrow-left" iconPos="left"/>
                    </div>
                </div>
                : <>
                    <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
                    <Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
                    <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
                    <Skeleton width="100%" height="4rem" className="mb-8"></Skeleton>
                    <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
                    <Skeleton width="100%" height="2rem" className="mb-8"></Skeleton>
                    <Skeleton width="20%" height="1rem" className="mb-2"></Skeleton>
                    <Skeleton width="100%" height="4rem"></Skeleton>
                </>}
        </div>
    )

}

export default BandoFormsPreview;