import React, { useMemo, useState, useCallback, useEffect, useRef } from 'react';
import { useForm, useFieldArray } from 'react-hook-form';
import { isEmpty, head, isNil } from 'ramda';
import { __ } from '@wordpress/i18n';
import { klona } from 'klona';
import { wrap } from 'object-path-immutable';
import { classNames } from 'primereact/utils';

// tools
import uniqid from '../../../../helpers/uniqid';
import formatDateString from '../../../../helpers/formatDateString';

// components
import FormField from '../../../../components/FormField';
import { Button } from 'primereact/button';
import { Dialog } from 'primereact/dialog';
import { Toast } from 'primereact/toast';
import { Dropdown } from 'primereact/dropdown';
import { InputText } from 'primereact/inputtext';
import { Calendar } from 'primereact/calendar';
import { FileUpload } from 'primereact/fileupload';
import CompanyDocsTable from './components/CompanyDocsTable';

// services
import CompanyDocumentsService from '../../../../service/company-documents-service';
import DocumentCategoryService from '../../../../service/document-category-service';
import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse';

const EvaluationExtraFiles = ({
                                  sourceId,
                                  applicationId,
                                  companyId,
                                  sourceName,
                                  updateFn = () => {
                                  },
                                  updateCallbackFn = () => {
                                  },
                                  refetchFn = () => {
                                  },
                                  defaultValue = [],
                                  shouldDisable = false
                              }) => {
    const [chosen, setChosen] = useState('');
    const [isVisibleCompanyDocsDialog, setIsVisibleCompanyDocsDialog] = useState(false);
    const [isVisibleAddDocDialog, setIsVisibleAddDocDialog] = useState(false);
    const [newDocData, setNewDocData] = useState({});
    const [docFileAttached, setDocFileAttached] = useState([]);
    const [documentCategories, setDocumentCategories] = useState([]);
    const [addDocLoading, setAddDocLoading] = useState(false);
    const [reloadHash, setReloadHash] = useState(0);
    const toast = useRef(null);
    const tomorrow = useMemo(() => {
        const d = new Date();
        d.setDate(d.getDate() + 1);
        return d;
    }, []);
    const {
        control,
        handleSubmit,
        formState: { errors },
        setValue,
        register,
        trigger,
        getValues,
        watch
    } = useForm({
        defaultValues: useMemo(() => {
            return {
                items: defaultValue || []
            };
        }, [defaultValue]), mode: 'onChange'
    });
    const { fields, append, remove } = useFieldArray({
        control,
        name: 'items'
    });

    const watchFields = watch('items');

    const onSubmit = () => {
    }

    const doUpdateAfterFileUploaded = () => {
        const formData = getValues();
        updateFn(formData.items);
        updateCallbackFn(formData.items);
    }

    const addNew = () => {
        const uid = uniqid('f');
        const newItem = {
            fieldId: uid,
            nameValue: '',
            fileValue: []
        }
        append(newItem);
        setChosen(newItem.fieldId);
        trigger();
    };

    const setNewChosen = useCallback((id) => {
        const chosenObj = head(fields.filter(o => id === o.fieldId));
        if (chosenObj) {
            setChosen(chosen === id ? '' : id);
        }
    }, [fields, chosen]);

    const removeItem = useCallback((index) => {
        const chosenObj = klona(fields[index]);
        remove(index);
        if (chosen === chosenObj.fieldId) {
            setChosen('');
        }
        const formData = getValues();
        updateFn(formData.items);
        updateCallbackFn(formData.items);
    }, [fields, chosen]);

    const openCompanyArchive = () => {
        setIsVisibleCompanyDocsDialog(true);
    }

    const headerCompanyDocsDialog = () => {
        return <span>{__('Documenti aziendali', 'gepafin')}</span>;
    }

    const hideCompanyDocsDialog = () => {
        setIsVisibleCompanyDocsDialog(false);
    }

    const footerCompanyDocsDialog = () => {
        return <div>
            <Button type="button" label={__('Chiudi', 'gepafin')} onClick={hideCompanyDocsDialog} outlined/>
        </div>
    }

    const openAddDocDialog = () => {
        setNewDocData({
            name: '',
            documentCategoryId: 0,
            expirationDate: ''
        });
        setDocFileAttached([]);
        setIsVisibleAddDocDialog(true);
    }

    const hideAddDocDialog = () => {
        setIsVisibleAddDocDialog(false);
        setNewDocData({});
        setDocFileAttached([]);
    }

    const headerAddDocDialog = () => {
        return <span>{__('Aggiungi documento aziendale', 'gepafin')}</span>;
    }

    const isDocFormValid = useCallback(() => {
        return !isEmpty(docFileAttached)
            && !isEmpty(newDocData.name) && !isNil(newDocData.name)
            && newDocData.documentCategoryId !== 0 && !isNil(newDocData.documentCategoryId)
            && !isEmpty(newDocData.expirationDate) && !isNil(newDocData.expirationDate);
    }, [docFileAttached, newDocData]);

    const footerAddDocDialog = () => {
        return <div>
            <Button type="button" label={__('Annulla', 'gepafin')} onClick={hideAddDocDialog} outlined/>
            <Button
                type="button"
                disabled={addDocLoading || !isDocFormValid()}
                label={__('Salva', 'gepafin')}
                onClick={doAddNewDoc}/>
        </div>
    }

    const onUpdateDocFieldValue = useCallback((value, name) => {
        setNewDocData(prev => wrap(prev).set([name], value).value());
    }, []);

    const onDocFileSelect = (file) => {
        setDocFileAttached(file.files);
    }

    const doAddNewDoc = useCallback(() => {
        const submitData = {
            ...newDocData,
            expirationDate: formatDateString(newDocData.expirationDate),
            documentType: 'COMPANY_DOCUMENT'
        };
        const queryParams = Object.keys(submitData).map(k => [k, submitData[k]]);

        if (!isEmpty(docFileAttached)) {
            const formData = new FormData();
            for (const file of docFileAttached) {
                formData.append('file', file);
            }
            setAddDocLoading(true);
            CompanyDocumentsService.uploadCompanyDocumenFromEvaluation(companyId, applicationId, formData, uploadDocCallback, errUploadDocCallback, queryParams);
        }
    }, [docFileAttached, newDocData, companyId, applicationId]);

    const uploadDocCallback = (resp) => {
        if (resp.status === 'SUCCESS') {
            hideAddDocDialog();
            setReloadHash(new Date().getTime());
            refetchFn();
        } else {
            if (toast.current && resp.message) {
                toast.current.show({
                    severity: 'error',
                    summary: '',
                    detail: resp.message
                });
            }
        }
        setAddDocLoading(false);
    }

    const errUploadDocCallback = (resp) => {
        if (toast.current && resp.message) {
            toast.current.show({
                severity: 'error',
                summary: '',
                detail: resp.message
            });
        }
        set404FromErrorResponse(resp);
        setAddDocLoading(false);
    }

    useEffect(() => {
        DocumentCategoryService.getCategories((resp) => {
            if (resp.status === 'SUCCESS') {
                setDocumentCategories(resp.data.map(o => ({ value: o.id, label: o.description })));
            }
        }, () => {});
    }, []);

    return (
        <>
            <div className="fieldsRepeater">
                <form className="appForm" onSubmit={handleSubmit(onSubmit)}>
                    {watchFields
                        ? watchFields.map((o, index) => <div key={o.fieldId}
                                                             className="fieldsRepeater__panel p-panel p-component">
                                <div className="fieldsRepeater__heading p-panel p-panel-header">
                                    <span onClick={() => setNewChosen(o.fieldId)}>{o.nameValue}</span>
                                    <Button icon="pi pi-times"
                                            disabled={shouldDisable}
                                            outlined
                                            severity="danger"
                                            className="actionBtn"
                                            type="button"
                                            aria-label={__('Cancella', 'gepafin')}
                                            onClick={() => removeItem(index)}/>
                                </div>
                                <div className="fieldsRepeater__fields p-panel-content" data-hide={chosen !== o.fieldId}>
                                    <FormField
                                        type="textinput"
                                        disabled={shouldDisable}
                                        fieldName={`items.${index}.nameValue`}
                                        label={__('Titolo del file', 'gepafin')}
                                        control={control}
                                        errors={errors}
                                        defaultValue={o.nameValue}
                                        config={{ required: __('È obbligatorio', 'gepafin') }}
                                    />
                                    <FormField
                                        type="fileupload"
                                        disabled={isEmpty(o.nameValue) || shouldDisable}
                                        setDataFn={setValue}
                                        saveFormCallback={doUpdateAfterFileUploaded}
                                        fieldName={`items.${index}.fileValue`}
                                        label={__('File', 'gepafin')}
                                        control={control}
                                        register={register}
                                        errors={errors}
                                        defaultValue={o.fileValue ? o.fileValue : []}
                                        accept={[]}
                                        source={sourceName}
                                        sourceId={sourceId}
                                        multiple={false}
                                        deleteOnBackend={true}
                                        config={{ required: __('È obbligatorio', 'gepafin') }}
                                    />
                                </div>
                            </div>
                        ) : null}
                </form>
                <div style={{ display: 'flex', gap: '10px' }}>
                    <Button
                        className="fieldsRepeater__addNew"
                        outlined
                        type="button"
                        disabled={(watchFields && watchFields.filter(o => isEmpty(o.nameValue) || isEmpty(o.fileValue)).length > 0) || shouldDisable}
                        onClick={addNew}
                        label={__('Aggiungi nuovo file', 'gepafin')}
                    />
                    <Button
                        className="fieldsRepeater__addNew"
                        outlined
                        type="button"
                        disabled={shouldDisable}
                        onClick={openCompanyArchive}
                        label={__('Documenti aziendali', 'gepafin')}
                    />
                </div>
            </div>
            <Toast ref={toast}/>
            <Dialog
                visible={isVisibleCompanyDocsDialog}
                modal
                header={headerCompanyDocsDialog}
                footer={footerCompanyDocsDialog}
                style={{ maxWidth: '900px', width: '100%' }}
                onHide={hideCompanyDocsDialog}>
                <div style={{ marginBottom: '1rem' }}>
                    <Button
                        type="button"
                        label={__('Aggiungi nuovo documento', 'gepafin')}
                        icon="pi pi-plus"
                        iconPos="right"
                        onClick={openAddDocDialog}/>
                </div>
                <CompanyDocsTable
                    type="COMPANY_DOCUMENT"
                    companyId={companyId}
                    applicationId={applicationId}
                    reload={reloadHash}
                    onImportSuccess={() => refetchFn()}/>
            </Dialog>
            <Dialog
                visible={isVisibleAddDocDialog}
                modal
                header={headerAddDocDialog}
                footer={footerAddDocDialog}
                style={{ maxWidth: '600px', width: '100%' }}
                onHide={hideAddDocDialog}>
                <div className="appForm__cols">
                    <div className="appForm__field">
                        <label
                            className={classNames({ 'p-error': isEmpty(newDocData.name) || isNil(newDocData.name) })}>
                            {__('Nome', 'gepafin')}*
                        </label>
                        <InputText
                            value={newDocData.name || ''}
                            invalid={isEmpty(newDocData.name || '') || isNil(newDocData.name)}
                            onChange={(e) => onUpdateDocFieldValue(e.target.value, 'name')}/>
                    </div>
                    <div className="appForm__field">
                        <label
                            className={classNames({ 'p-error': !newDocData.documentCategoryId || newDocData.documentCategoryId === 0 })}>
                            {__('Categoria', 'gepafin')}*
                        </label>
                        <Dropdown
                            value={newDocData.documentCategoryId}
                            invalid={!newDocData.documentCategoryId || newDocData.documentCategoryId === 0}
                            onChange={(e) => onUpdateDocFieldValue(e.value, 'documentCategoryId')}
                            options={documentCategories}
                            optionLabel="label"
                            optionValue="value"/>
                    </div>
                </div>
                <div className="appForm__cols">
                    <div className="appForm__field">
                        <label
                            className={classNames({ 'p-error': isEmpty(newDocData.expirationDate || '') || isNil(newDocData.expirationDate) })}>
                            {__('Scadenza', 'gepafin')}*
                        </label>
                        <Calendar
                            value={newDocData.expirationDate}
                            minDate={tomorrow}
                            invalid={isEmpty(newDocData.expirationDate || '') || isNil(newDocData.expirationDate)}
                            onChange={(e) => onUpdateDocFieldValue(e.value, 'expirationDate')}/>
                    </div>
                </div>
                <div className="appForm__cols">
                    <div className="appForm__field">
                        <label
                            className={classNames({ 'p-error': isEmpty(docFileAttached) })}>
                            {__('File', 'gepafin')}*
                        </label>
                        <FileUpload
                            mode="basic"
                            name="file"
                            onSelect={onDocFileSelect}/>
                    </div>
                </div>
            </Dialog>
        </>
    )
}

export default EvaluationExtraFiles;
