import React, { useEffect, useState } from 'react';
import { head, isEmpty, isNil, uniq } from 'ramda';
import { __, sprintf } from '@wordpress/i18n';
import { klona } from 'klona';
import { wrap } from 'object-path-immutable';

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

// components
import { InputText } from 'primereact/inputtext';
import { Button } from 'primereact/button';
import { Tag } from 'primereact/tag';
import { TabView, TabPanel } from 'primereact/tabview';
import { InputSwitch } from 'primereact/inputswitch';
import ElementSetting from './components/ElementSetting';
import { Dropdown } from 'primereact/dropdown';
import { MultiSelect } from 'primereact/multiselect';

import { dynamicDataOptions } from '../../../../configData';
import { InputNumber } from 'primereact/inputnumber';

const BuilderElementSettings = ({ closeSettingsFn, callStatus, context }) => {
    const elements = useStoreValue('formElements');
    const activeElement = useStoreValue('activeElement');
    const criteriaOptions = useStoreValue('bandoCriteria');
    const [activeElementData, setActiveElementData] = useState({});
    const [settings, setSettings] = useState([]);
    const [validators, setValidators] = useState({});
    const [dynamicData, setDynamicData] = useState([]);
    const [criteria, setCriteria] = useState([]);
    const [labelError, setLabelError] = useState(false);
    const numberBasedValidatorFields = ['min', 'max', 'minLength', 'maxLength'];
    const customValidationOptions = [
        { value: 'isPIVA', label: 'isPIVA' },
        { value: 'isCodiceFiscale', label: 'isCodiceFiscale' },
        { value: 'isCAP', label: 'isCAP' },
        { value: 'isIBAN', label: 'isIBAN' },
        { value: 'isEmail', label: 'isEmail' },
        { value: 'isEmailPEC', label: 'isEmailPEC' },
        { value: 'isUrl', label: 'isUrl' },
        { value: 'isMarcaDaBollo', label: 'isMarcaDaBollo' },
        { value: 'minChecks', label: 'minChecks' },
        { value: 'maxChecks', label: 'maxChecks' },
        { value: 'nonEmptyTables', label: 'nonEmptyTables' }
    ]

    const hasAnyValidation = !isEmpty(validators) && (
        validators.isRequired === true ||
        Object.entries(validators)
            .filter(([k]) => k !== 'isRequired')
            .some(([, v]) => !isNil(v))
    );

    const onChange = (value, name) => {
        if (name === 'label' && labelError) {
            setLabelError(false);
        }

        const newSettings = settings
            .map(o => {
                if (o.name === name) {
                    o.value = value;
                }

                return o;
            });

        setSettings(newSettings);
        storeSet('chosenFieldSettings', newSettings);
    }

    const onUpdateOptions = (name, value) => {
        const newSettings = settings
            .map(o => {
                if (o.name === name) {
                    o.value = value;
                }

                return o;
            });

        setSettings(newSettings);
        storeSet('chosenFieldSettings', newSettings);
    }

    const saveSettings = () => {
        const latestSettings = storeGet('chosenFieldSettings') || settings;

        if (hasAnyValidation) {
            const labelSetting = head(latestSettings.filter(o => o.name === 'label'));
            if (labelSetting && isEmpty(labelSetting.value.trim())) {
                setLabelError(true);
                return;
            }
        }
        setLabelError(false);

        let newActiveElementData = klona(activeElementData);
        // Prefer the store value over React state: child components (e.g. ElementSettingSpreadsheet)
        // write to the store synchronously, but React state updates are batched and may lag behind
        // when saveSettings is called in the same event as the last setDataFn call.
        newActiveElementData = wrap(newActiveElementData).set(['settings'], latestSettings).value();
        newActiveElementData = wrap(newActiveElementData).set(['validators'], validators).value();
        newActiveElementData = wrap(newActiveElementData).set(['dynamicData'], dynamicData).value();
        newActiveElementData = wrap(newActiveElementData).set(['criteria'], criteria).value();
        const newElements = elements.map(o => o.id === newActiveElementData.id ? newActiveElementData : o);

        storeSet('formElements', newElements);
        closeSettingsFn();
    }

    const showField = (value, key) => {
        let newValidators = klona(validators);
        if (value) {
            newValidators[key] = '';
        } else {
            newValidators[key] = null;
        }
        setValidators(newValidators);
    }

    const toggleRequired = (value, key) => {
        let newValidators = klona(validators);
        newValidators[key] = value;
        setValidators(newValidators);
    }

    const onChangeValidator = (value, name) => {
        let newValidators = klona(validators);
        newValidators[name] = value;
        setValidators(newValidators);
    }

    const onChangeCriteriaData = (value) => {
        setCriteria(value);
    }

    const getDynamicDataOptions = (type) => {
        return dynamicDataOptions[type] ?? [];
    }

    useEffect(() => {
        const chosen = head(elements.filter(o => o.id === activeElement));
        const elementItems = storeGet('elementItems');
        const chosenElementItemCfg = head(elementItems.filter(o => o.name === chosen.name));
        let settings = [];

        if (chosenElementItemCfg && chosenElementItemCfg.settings) {
            settings = chosenElementItemCfg.settings.map((o) => {
                const setting = head(chosen.settings.filter(s => s.name === o.name));
                return setting ? klona(setting) : klona(o)
            });
        }

        settings = uniq([...settings, ...chosen.settings]).filter(o => context === 'call'
            ? !['isRequestedAmount', 'isDelegation', ''].includes(o.name)
            : !['isChecklistItem'].includes(o.name));

        if (chosen) {
            setActiveElementData(klona(chosen));
            setSettings(settings);
            storeSet('chosenFieldSettings', settings);
            setValidators(klona(chosen.validators));
            setDynamicData(chosen.dynamicData ? chosen.dynamicData : '');
            setCriteria(chosen.criteria ? chosen.criteria : []);
        } else {
            setActiveElementData({});
            setSettings([]);
            setValidators({});
            setDynamicData([]);
            setCriteria([]);
        }
    }, [activeElement]);

    return (activeElementData
            ? <div className="formElementSettings">
                <Tag value={activeElementData.name} severity="info"/>
                <TabView className="formElementSettings__tabs">
                    <TabPanel header={__('Presentation', 'gepafin')}>
                        {settings
                            ? settings
                                .filter(o => ![
                                    'variable', 'formula', 'reportEnable', 'reportHeader', 'reportColumns'
                                ].includes(o.name))
                                .map((o) => <ElementSetting
                                    key={o.name}
                                    setting={o}
                                    context={context}
                                    callStatus={callStatus}
                                    changeFn={onChange}
                                    updateDataFn={onUpdateOptions}
                                    required={o.name === 'label' && hasAnyValidation}
                                    hasError={o.name === 'label' && labelError && hasAnyValidation}/>)
                            : null}
                        {!isNil(dynamicDataOptions[activeElementData.name]) && context === 'application'
                            ? <div className="formElementSettings__field">
                                <label htmlFor="dynamicData">{__('Dati dinamici', 'gepafin')}</label>
                                <Dropdown
                                    id="dynamicData"
                                    value={dynamicData}
                                    filter
                                    onChange={(e) => setDynamicData(e.value)}
                                    options={getDynamicDataOptions(activeElementData.name)}
                                    optionLabel="label"
                                    optionValue="value"
                                    showClear
                                    placeholder={__('Scegli', 'gepafin')}/>
                            </div> : null}
                    </TabPanel>
                    {!isEmpty(validators)
                        ? <TabPanel header={__('Validation', 'gepafin')}>
                            {validators
                                ? Object.keys(validators).map((k) => <div
                                    className="formElementSettings__field" key={k}>
                                    {k === 'isRequired'
                                        ? <div className="formElementSettings__field">
                                            <label htmlFor={k}>{__('Obligatorio?', 'gepafin')}</label>
                                            <InputSwitch
                                                checked={validators[k]}
                                                onChange={(e) => toggleRequired(e.value, k)}/>
                                        </div>
                                        : null}
                                    {numberBasedValidatorFields.includes(k) || 'pattern' === k || 'custom' === k
                                        ? <div className="formElementSettings__field">
                                            <label htmlFor={`enable_${k}`}>{sprintf(__('Set %s', 'gepafin'), k)}</label>
                                            <InputSwitch
                                                checked={!isNil(validators[k])}
                                                onChange={(e) => showField(e.value, k)}/>
                                        </div>
                                        : null}
                                    {k === 'custom' && !isNil(validators[k])
                                        ? <div className="formElementSettings__field">
                                            <label htmlFor={k}>{__('Personalizzato', 'gepafin')}</label>
                                            <Dropdown
                                                id={`enable_${k}`}
                                                value={validators[k]}
                                                onChange={(e) => onChangeValidator(e.value, k)}
                                                options={customValidationOptions}
                                                optionLabel="label"
                                                optionValue="value"
                                                showClear
                                                placeholder={__('Scegli', 'gepafin')}/>
                                        </div>
                                        : null}
                                    {'pattern' === k && !isNil(validators[k])
                                        ? <div className="formElementSettings__field">
                                            <label htmlFor={k}>{k}</label>
                                            <InputText id={k} aria-describedby={`${k}-help`}
                                                       value={validators[k]}
                                                       onChange={(e) => onChangeValidator(e.target.value, k)}/>
                                        </div> : null}
                                    {['min', 'max'].includes(k) && !isNil(validators[k])
                                        ? <div className="formElementSettings__field">
                                            <label htmlFor={k}>{k}</label>
                                            <InputNumber id={k}
                                                         aria-describedby={`${k}-help`}
                                                         value={validators[k]}
                                                         locale="it-IT"
                                                         minFractionDigits={2}
                                                         placeholder="0"
                                                         onChange={(e) => onChangeValidator(e.value, k)}/>
                                        </div> : null}
                                    {['minLength', 'maxLength'].includes(k) && !isNil(validators[k])
                                        ? <div className="formElementSettings__field">
                                            <label htmlFor={k}>{k}</label>
                                            <InputText id={k}
                                                       aria-describedby={`${k}-help`}
                                                       value={validators[k]}
                                                       keyfilter="int"
                                                       placeholder="0"
                                                       onChange={(e) => onChangeValidator(e.target.value, k)}/>
                                        </div> : null}
                                </div>) : null}
                        </TabPanel> : null}
                    {context === 'application'
                        ? <TabPanel header={__('Criteri', 'gepafin')}>
                            <div className="formElementSettings__field">
                                <label htmlFor="criteria">{__('Criteri di valutazione', 'gepafin')}</label>
                                <MultiSelect
                                    id="criteria"
                                    value={criteria}
                                    onChange={(e) => onChangeCriteriaData(e.value)}
                                    options={criteriaOptions}
                                    optionLabel="label"
                                    optionValue="value"
                                    display="chip"
                                    placeholder={__('Scegli', 'gepafin')}/>
                            </div>
                        </TabPanel> : null}
                    {settings && settings
                        .filter(o => ['variable', 'formula'].includes(o.name)).length > 0
                        ? <TabPanel header={__('Calcolo', 'gepafin')}>
                            {settings
                                ? settings
                                    .filter(o => ['variable', 'formula'].includes(o.name))
                                    .map((o) => <ElementSetting
                                        key={o.name}
                                        setting={o}
                                        context={context}
                                        callStatus={callStatus}
                                        changeFn={onChange}
                                        updateDataFn={onUpdateOptions}/>)
                                : null}
                        </TabPanel> : null}
                    <TabPanel header={__('Rapporto CSV', 'gepafin')}>
                        {settings
                            ? settings
                                .filter(o => ['reportEnable', 'reportHeader', 'reportColumns'].includes(o.name))
                                .map((o) => <ElementSetting
                                    key={o.name}
                                    setting={o}
                                    context={context}
                                    callStatus={callStatus}
                                    changeFn={onChange}
                                    updateDataFn={onUpdateOptions}/>)
                            : null}
                    </TabPanel>
                </TabView>

                <div style={{ display: 'flex', gap: '0.5rem' }}>
                    <Button label={__('Annulla', 'gepafin')} onClick={closeSettingsFn} severity="danger"/>
                    <Button label={__('Salva', 'gepafin')} onClick={saveSettings}/>
                </div>
            </div>
            : null
    )
}

export default BuilderElementSettings;