import React, { useState, useEffect, useRef, useCallback } from 'react';
import { __ } from '@wordpress/i18n';
import { head, isEmpty, isNil } from 'ramda';
import { klona } from 'klona';

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

// service
import UserService from '../../service/user-service';

// tools
import set404FromErrorResponse from '../../helpers/set404FromErrorResponse';
import { isCodiceFiscale, isEmail, isPIVA } from '../../helpers/validators';

// components
import AllUsersTable from './components/AllUsersTable';
import { Button } from 'primereact/button';
import { InputText } from 'primereact/inputtext';
import { Dropdown } from 'primereact/dropdown';
import { Dialog } from 'primereact/dialog';
import { classNames } from 'primereact/utils';
import { Toast } from 'primereact/toast';
import uniqid from '../../helpers/uniqid';

const APP_HUB_ID = process.env.REACT_APP_HUB_ID;

const Users = () => {
    const [loading, setLoading] = useState(false);
    const [isVisibleEditDialog, setIsVisibleEditDialog] = useState(false);
    const [updaterString, setUpdaterString] = useState('');
    const [newUserData, setNewUserData] = useState({
        firstName: '',
        lastName: '',
        email: '',
        phoneNumber: '',
        password: '',
        confPassword: '',
        roleId: 0,
        codiceFiscale: '',
        privacy: true,
        terms: true
    });
    const [roles, setRoles] = useState([]);
    const toast = useRef(null);

    const onCreateNewUser = () => {
        setIsVisibleEditDialog(true);
    }

    const headerEditDialog = () => {
        return <span>{__('Aggiungi utente', 'gepafin')}</span>
    }

    const hideEditDialog = () => {
        setIsVisibleEditDialog(false);
        setNewUserData({
            firstName: '',
            lastName: '',
            email: '',
            phoneNumber: '',
            password: '',
            confPassword: '',
            roleId: 0,
            codiceFiscale: '',
            privacy: true,
            terms: true
        });
    }

    const saveEditDialog = () => {
        const isConfidi = isConfidiRoleChosen();
        const emptyValues = Object.keys(newUserData)
            .filter(v => v !== 'phoneNumber')
            .filter(v => isConfidi ? v : v !== 'codiceFiscale')
            .filter(v => isInvalidField(newUserData, v));

        if (isEmpty(emptyValues) && newUserData.password === newUserData.confPassword && !loading) {
            setLoading(true);
            let body = klona({
                ...newUserData,
                hubUuid: APP_HUB_ID
            });

            if (!isConfidi) {
                delete body.codiceFiscale;
            }

            UserService.createUser(body, createUserCallback, errCreateUserCallback);
        }
    }

    const createUserCallback = (data) => {
        if (data.status === 'SUCCESS') {
            const users = storeGet('users');
            storeSet('users', [data.data.user, ...users]);
            if (toast.current) {
                toast.current.show({
                    severity: 'success',
                    summary: '',
                    detail: data.message
                });
            }
        }
        setUpdaterString(uniqid());
        setLoading(false);
        hideEditDialog();
    }

    const errCreateUserCallback = (data) => {
        setLoading(false);
        if (toast.current) {
            toast.current.show({
                severity: 'error',
                summary: '',
                detail: data.message
            });
        }
        set404FromErrorResponse(data);
    }

    const onChangeEditItem = (value, key) => {
        const userData = klona(newUserData);
        userData[key] = value;
        setNewUserData(userData);
    }

    const footerEditDialog = useCallback(() => {
        const isConfidi = isConfidiRoleChosen();
        const errorValues = Object.keys(newUserData)
            .filter(v => v !== 'phoneNumber')
            .filter(v => isConfidi ? v : v !== 'codiceFiscale')
            .filter(v => isInvalidField(newUserData, v));

        return <div>
            <Button type="button" label={__('Annulla', 'gepafin')} onClick={hideEditDialog} outlined/>
            <Button
                type="button"
                disabled={!isEmpty(errorValues) || loading}
                label={__('Salva', 'gepafin')} onClick={saveEditDialog}/>
        </div>
    }, [newUserData]);

    const getRolesCallback = (data) => {
        if (data.status === 'SUCCESS') {
            const roles = data.data
                .filter(o => [
                    'ROLE_SUPER_ADMIN', 'ROLE_PRE_INSTRUCTOR', 'ROLE_INSTRUCTOR_MANAGER', 'ROLE_CONFIDI', 'ROLE_DIRECTOR'
                ].includes(o.roleType))
                .map(o => ({
                    name: o.roleName,
                    value: o.id,
                    id: o.id,
                    roleType: o.roleType
                }));
            setRoles(roles);
        }
        storeSet('unsetAsyncRequest');
    }

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

    const isInvalidField = (data, key) => key === 'codiceFiscale'
        ? !isCodiceFiscale(data[key]) && !isPIVA(data[key])
        : isEmpty(data[key]) || isNil(data[key]);

    const isConfidiRoleChosen = useCallback(() => {
        const chosen = head(roles.filter(o => o.id === newUserData.roleId));
        return chosen ? chosen.roleType === 'ROLE_CONFIDI' : false;
    }, [roles, newUserData])

    useEffect(() => {
        if (isVisibleEditDialog) {
            UserService.getRoles(getRolesCallback, errGetRolesCallback)
        }
    }, [isVisibleEditDialog]);

    return (
        <div className="appPage">
            <div className="appPage__pageHeader">
                <h1>{__('Gestione utenti', 'gepafin')}</h1>
            </div>

            <div className="appPage__spacer"></div>
            <Toast ref={toast}/>

            <div className="appPageSection">
                <div className="appPageSection__actions">
                    <Button
                        onClick={onCreateNewUser}
                        label={__('Crea nuovo')} icon="pi pi-plus" iconPos="right"/>
                </div>

                <AllUsersTable updaterString={updaterString}/>

                <Dialog
                    visible={isVisibleEditDialog}
                    modal
                    header={headerEditDialog}
                    footer={footerEditDialog}
                    style={{ maxWidth: '600px', width: '100%' }}
                    onHide={hideEditDialog}>
                    <div className="appPage__spacer"></div>
                    <div className="appForm__cols">
                        <div className="appForm__field">
                            <label
                                className={classNames({ 'p-error': isInvalidField(newUserData, 'firstName') })}>
                                {__('Nome', 'gepafin')}*
                            </label>
                            <InputText value={newUserData.firstName}
                                       invalid={isInvalidField(newUserData, 'firstName')}
                                       onChange={(e) => onChangeEditItem(e.target.value, 'firstName')}/>
                        </div>
                        <div className="appForm__field">
                            <label
                                className={classNames({ 'p-error': isInvalidField(newUserData, 'lastName') })}>
                                {__('Cognome', 'gepafin')}*
                            </label>
                            <InputText value={newUserData.lastName}
                                       invalid={isInvalidField(newUserData, 'lastName')}
                                       onChange={(e) => onChangeEditItem(e.target.value, 'lastName')}/>
                        </div>
                    </div>
                    <div className="appForm__cols">
                        <div className="appForm__field">
                            <label
                                className={classNames({ 'p-error': isEmpty(newUserData.email) || isNil(newUserData.email) || !isEmail(newUserData.email) })}>
                                {__('Email', 'gepafin')}*
                            </label>
                            <InputText value={newUserData.email}
                                       invalid={isEmpty(newUserData.email) || isNil(newUserData.email) || !isEmail(newUserData.email)}
                                       onChange={(e) => onChangeEditItem(e.target.value, 'email')}/>
                        </div>
                        <div className="appForm__field">
                            <label>
                                {__('Telefono', 'gepafin')}
                            </label>
                            <InputText value={newUserData.phoneNumber}
                                       keyfilter="int"
                                       onChange={(e) => onChangeEditItem(e.target.value, 'phoneNumber')}/>
                        </div>
                    </div>
                    <div className="appForm__cols">
                        <div className="appForm__field">
                            <label
                                className={classNames({ 'p-error': isEmpty(newUserData.password) || isNil(newUserData.password) || newUserData.password !== newUserData.confPassword })}>
                                {__('Password', 'gepafin')}*
                            </label>
                            <InputText value={newUserData.password}
                                       invalid={isEmpty(newUserData.password) || isNil(newUserData.password) || newUserData.password !== newUserData.confPassword}
                                       onChange={(e) => onChangeEditItem(e.target.value, 'password')}/>
                        </div>
                        <div className="appForm__field">
                            <label
                                className={classNames({ 'p-error': isEmpty(newUserData.confPassword) || isNil(newUserData.confPassword) || newUserData.password !== newUserData.confPassword })}>
                                {__('Conferma password', 'gepafin')}*
                            </label>
                            <InputText value={newUserData.confPassword}
                                       invalid={isEmpty(newUserData.confPassword) || isNil(newUserData.confPassword) || newUserData.password !== newUserData.confPassword}
                                       onChange={(e) => onChangeEditItem(e.target.value, 'confPassword')}/>
                        </div>
                    </div>
                    <div className="appForm__field">
                        <label
                            className={classNames({ 'p-error': isEmpty(newUserData.roleId) || isNil(newUserData.roleId) || newUserData.roleId === 0 })}>
                            {__('Ruolo', 'gepafin')}*
                        </label>
                        <Dropdown
                            value={newUserData.roleId}
                            invalid={isEmpty(newUserData.roleId) || isNil(newUserData.roleId) || newUserData.roleId === 0}
                            onChange={(e) => onChangeEditItem(e.value, 'roleId')}
                            options={roles}
                            optionLabel="name"
                            optionValue="value"/>
                    </div>
                    {isConfidiRoleChosen()
                        ? <div className="appForm__field">
                            <label
                                className={classNames({ 'p-error': isInvalidField(newUserData, 'codiceFiscale') })}>
                                {__('Codice Fiscale', 'gepafin')}*
                            </label>
                            <InputText value={newUserData.codiceFiscale}
                                       invalid={isInvalidField(newUserData, 'codiceFiscale')}
                                       onChange={(e) => onChangeEditItem(e.target.value, 'codiceFiscale')}/>
                        </div> : null}
                    <div className="appPage__spacer"></div>
                </Dialog>
            </div>
        </div>
    )
}

export default Users;