import React, { useEffect, useState, useRef } from 'react';
import { classNames } from 'primereact/utils';
import { head, isEmpty } from 'ramda'
import { __ } from '@wordpress/i18n';

// api
import FileUploadService from '../../../../service/file-upload-service';

// tools
import getPropeMimeLabels from '../../../../helpers/getPropeMimeLabels';

// components
import { FileUpload } from 'primereact/fileupload';
import { Tag } from 'primereact/tag';
import { Button } from 'primereact/button';
import { Messages } from 'primereact/messages';

import { defaultMaxFileSize, mimeTypes } from '../../../../configData';
import getFormatedFileSizeText from '../../../../helpers/getFormatedFileSizeText';
import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup';

const Fileupload = ({
                        fieldName,
                        setDataFn,
                        label,
                        errors,
                        register,
                        defaultValue = [],
                        config = {},
                        infoText = null,
                        accept = ['image/*'],
                        doctype = 'document',
                        maxSize = defaultMaxFileSize,
                        emptyText = __('Trascina qui il tuo file', 'gepafin'),
                        chooseLabel = __('Aggiungi file', 'gepafin'),
                        uploadLabel = __('Salva documento', 'gepafin'),
                        cancelLabel = __('Cancella documento', 'gepafin'),
                        multiple = false,
                        sourceId = 0,
                        source = 'application',
                        disabled = false,
                        saveFormCallback = () => {
                        },
                        deleteOnBackend = true
                    }) => {
    // eslint-disable-next-line no-unused-vars
    const [stateFieldData, setStateFieldData] = useState([]);
    const [acceptFormats, setAcceptFormats] = useState('');
    const [formatsForInput, setFormatsForInput] = useState('');
    const inputRef = useRef();
    const messagesRef = useRef(null);

    const customBase64Uploader = (event) => {
        const formData = new FormData()
        const filesToUpload = [];
        const uploadedFiles = inputRef.current ? inputRef.current.getUploadedFiles() : [];
        const currentFiles = stateFieldData;

        for (const file of event.files) {
            const isDuplicate = [...uploadedFiles, ...currentFiles].some(
                (uploadedFile)=>uploadedFile.name === file.name
            );

            if(isDuplicate){
                messagesRef.current.show({
                    severity: 'error',
                    summary: __('Attenzione', 'gepafin'),
                    detail: `Il file con nome "${file.name}" è già stato caricato.`,
                    life: 10000
                });
            } else {
                formData.append('file', file)
                filesToUpload.push(file);
            }
            
        }
        if(filesToUpload.length > 0 ){
            FileUploadService.uploadFile(sourceId, formData, callback, errorCallback, [
                ['documentType', doctype.toUpperCase()],
                ['sourceType', source.toUpperCase()]
            ]);
        }
    };

    const callback = (data, uploadedFiles) => {
        if (data.status === 'SUCCESS') {
            setStateFieldData(prevState => [...prevState, ...data.data]);
            const currentUploadedFiles = inputRef.current.getUploadedFiles() || [];
            inputRef.current.setFiles([]);
            
            setDataFn(fieldName, [...currentUploadedFiles, ...data.data], { shouldValidate: true });
            
            saveFormCallback();
        }
    }

    const errorCallback = (err) => {
        console.log('err', err);
    }

    const confirmDelete = (event, file) => {
        confirmPopup({
            target: event.currentTarget,
            message: __('Sei sicuro di cancellare il file?', 'gepafin'),
            acceptLabel: __('Si', 'gepafin'),
            icon: 'pi pi-info-circle',
            defaultFocus: 'reject',
            acceptClassName: 'p-button-danger',
            accept: () => onTemplateRemove(file),
            reject: () => {}
        });
    };

    const itemTemplate = (file) => {
        let fileName = file.fileName ? file.fileName : file.name;
        return (
            <div className="appForm__fileUploadItem">
                <div>
                    <span className="appForm__fileUploadItemName">
                        {fileName}
                    </span>
                </div>
                <div>
                    {file.id ? <Tag value={__('Caricato', 'gepafin')} severity="success"></Tag> : null}
                    {!file.id ? <Tag value={__('In attesa', 'gepafin')} severity="warning"></Tag> : null}
                </div>
                <div>
                    <Button icon="pi pi-times"
                            severity="danger"
                            type="button"
                            disabled={disabled}
                            aria-label={__('Annulla', 'gepafin')}
                            onClick={(e) => confirmDelete(e, file)}/>
                </div>
            </div>
        );
    };

    const onTemplateRemove = (file) => {
        if (file.id && deleteOnBackend) {
            FileUploadService.deleteFile(
                {},
                (data) => deleteCallback(data, file.id),
                deleteErrorCallback,
                [['id', file.id]]
            );
        } else {
            const files = inputRef.current.getFiles()
            const newFiles = files.filter(o => o.lastModified !== file.lastModified && o.name !== file.name);
            inputRef.current.setFiles(newFiles);
            if (file.id) {
                const uploadedFiles = inputRef.current.getUploadedFiles();
                const newUploadedFiles = uploadedFiles.filter(o => o.id !== file.id);
                inputRef.current.setUploadedFiles(newUploadedFiles);
            }
        }
    }

    const deleteCallback = (data, id) => {
        if (data.status === 'SUCCESS') {
            setStateFieldData(prevState => {
                const newFiles = prevState.filter(o => o.id !== id);
                setDataFn(fieldName, newFiles, { shouldValidate: true });
                saveFormCallback();
                return newFiles;
            });
        }
    }

    const deleteErrorCallback = (err) => {
        console.log('err', err);
    }

    const onBeforeDrop = (e) => {
        return !isEmpty(e.dataTransfer.files) ? validateFileInputType(e.dataTransfer.files) : false;
    }

    const onBeforeSelect = (e) => {
        if (e.originalEvent.target.files) {
            return !isEmpty(e.originalEvent.target.files)
                ? validateFileInputType(e.originalEvent.target.files)
                : false;
        }
    }

    const validateFileInputType = (files) => {
        const MIMEtype = new RegExp(acceptFormats);

        return Array.prototype.every.call(files, function passesAcceptedFormat(file) {
            const fileExtension = `.${file.name.split('.').pop().toLowerCase()}`;
            const fileType = file.type;
            if (file.size === 0) {
                alert('Il file non è valido');
            }
            return file.size > 0 && (MIMEtype.test(fileType) || MIMEtype.test(fileExtension));
        });
    }

    useEffect(() => {
        setStateFieldData(defaultValue);
        register(fieldName, config)
    }, []);

    useEffect(() => {
        if (inputRef.current) {
            inputRef.current.setUploadedFiles(defaultValue);
        }
        setStateFieldData(defaultValue);
    }, [defaultValue]);

    useEffect(() => {
        const properMime = accept.map
            ? accept
                .map(v => {
                    const found = head(mimeTypes.filter(o => o.code.includes(v)));
                    let res = v;

                    if (found) {
                        res = found.code;
                    }

                    return res;
                }) : [];
        // eslint-disable-next-line no-useless-escape
        setAcceptFormats(properMime.join(',').replace(/\*/g, '.\*').replace(/,/g, '|'));
        setFormatsForInput(properMime.join(','));
    }, [accept]);

    return (
        sourceId || sourceId === 0
            ? <>
                <Messages ref={messagesRef} /> 
                <label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
                    {label}{config.required || config.isRequired ?
                    <span className="appForm__field--required">*</span> : null}
                    {acceptFormats ? ' (' + getPropeMimeLabels(accept) + ')' : null}
                    {` (max ${getFormatedFileSizeText(maxSize)})`}
                </label>
                <FileUpload
                    ref={inputRef}
                    disabled={disabled}
                    id={fieldName}
                    name={fieldName}
                    url={'/document/uploadFile'}
                    multiple={multiple}
                    accept={formatsForInput}
                    maxFileSize={maxSize}
                    emptyTemplate={<p>{emptyText}</p>}
                    chooseLabel={chooseLabel}
                    cancelLabel={cancelLabel}
                    uploadLabel={uploadLabel}
                    className={classNames({ 'p-invalid': errors[fieldName] })}
                    itemTemplate={itemTemplate}
                    customUpload
                    onBeforeDrop={onBeforeDrop}
                    onBeforeSelect={onBeforeSelect}
                    uploadHandler={customBase64Uploader}/>
                {infoText ? <small>{infoText}</small> : null}
                <ConfirmPopup />
            </>
            : null
    )
}

export default Fileupload;