import React, { useEffect, useState, useCallback } from 'react';
import { classNames } from 'primereact/utils';
import { __ } from '@wordpress/i18n';
import { pathOr, isEmpty, isNil } from 'ramda';
import { wrap } from 'object-path-immutable';
import equal from 'fast-deep-equal';

//components
import { Button } from 'primereact/button';
import RenderTable from './RenderTable';
import { klona } from 'klona';
import { nonEmptyTables } from '../../../../helpers/validators';
import NumericFormulaCell from './RenderTable/components/NumericFormulaCell';

const Table = ({
                   fieldName,
                   setDataFn,
                   label,
                   register,
                   errors,
                   disabled = false,
                   config = {},
                   defaultValue = [],
                   tableColumns = []
               }) => {
    const [columnsCfg, setColumnsCfg] = useState([]);
    const [rowsCfg, setRowsCfg] = useState([]);
    const [columns, setColumns] = useState([]);
    const [lastRow, setLastRow] = useState([]);
    const [rows, setRows] = useState(null);
    const [shouldDisableNewRows, setShouldDisableNewRows] = useState(false);
    const [rowIndexToDelete, rowRowIndexToDelete] = useState(null);

    const addNewRow = () => {
        if (disabled) {
            return;
        }
        const obj = columnsCfg
            .reduce((acc, cur) => {
                acc[cur.name] = ''
                return acc;
            }, {});
        const newRowsData = [...rows, obj];
        updateRows(newRowsData);
    }

    const removeRow = (index) => {
        rowRowIndexToDelete(index);
    }

    const updateRows = useCallback((data) => {
        setRows(data);
        setDataFn(fieldName, data, { shouldValidate: true });
    }, [rows, defaultValue]);

    const properConfig = (config) => {
        let newConfig = klona(config);
        if (config.validate && config.validate.nonEmptyTables) {
            newConfig = wrap(newConfig)
                .set(['validate', 'nonEmptyTables'], (v) => nonEmptyTables(v, tableColumns))
                .value();
        }

        return newConfig;
    }

    useEffect(() => {
        if (!isNil(rowIndexToDelete)) {
            const newRowsData = wrap(rows).del([rowIndexToDelete]).value();
            updateRows(newRowsData);
        }
        rowRowIndexToDelete(null);
    }, [rowIndexToDelete]);

    useEffect(() => {
        let shouldDisableNewRows = false;
        let newColumns = columnsCfg.map((o) => {
            const item = {
                accessorKey: o.name,
                header: () => o.label,
                footer: (props) => props.column.id,
                meta: {
                    predefined: o.predefined,
                    enableFormula: o.enableFormula,
                    fieldtype: o.fieldtype
                }
            }

            if (o.predefined) {
                shouldDisableNewRows = true;
                item.cell = (info) => info.getValue();
            } else if (o.enableFormula || o.fieldtype === 'numeric') {
                item.cell = NumericFormulaCell;
            }

            return item;
        });

        setShouldDisableNewRows(shouldDisableNewRows);

        if (!shouldDisableNewRows && !isEmpty(newColumns)) {
            newColumns.push({
                accessorKey: 'actions',
                header: () => '',
                footer: (props) => props.column.id,
                cell: ({ row: { index } }) => <Button
                    disabled={disabled}
                    type="button"
                    icon="pi pi-times"
                    className="p-button-danger"
                    label=""
                    onClick={() => removeRow(index)}/>
            })
        }

        setColumns(newColumns);
    }, [columnsCfg, disabled]);

    useEffect(() => {
        const stateFieldData = pathOr([], ['stateFieldData'], tableColumns);
        let rowsData = pathOr([], ['rowsData'], tableColumns);

        setColumnsCfg(stateFieldData);
        setRowsCfg(rowsData);

        let lastRowData = stateFieldData.reduce((acc, cur) => {
            const value = cur.enableFormula ? cur.lastRowFormula : (cur.lastRowText ? cur.lastRowText : '');
            acc.push({ [cur.name]: value });
            return acc;
        }, []);

        if (!shouldDisableNewRows) {
            lastRowData.push({ actions: '' })
        }

        const lastRowValues = lastRowData
            .map(o => {
                const values = Object.values(o);
                return values[0];
            })
            .filter(v => !isEmpty(v));

        setLastRow(!isEmpty(lastRowValues) ? lastRowData : []);
    }, [tableColumns, shouldDisableNewRows]);

    // Saved data (defaultValue) takes priority over template defaults (rowsCfg).
    // Using a single effect for both so the second render caused by rowsCfg changing
    // doesn't overwrite the saved data that was just loaded from the API.
    useEffect(() => {
        const next = (defaultValue && !isEmpty(defaultValue)) ? defaultValue : rowsCfg;
        if (!equal(rows, next)) {
            setRows(next);
        }
    }, [rowsCfg, defaultValue]); // eslint-disable-line react-hooks/exhaustive-deps

    useEffect(() => {
        register(fieldName, properConfig(config));
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    return (
        <>
            <label htmlFor={fieldName} className={classNames({ 'p-error': errors[fieldName] })}>
                {label}{config.required || config.isRequired || (config.validate && config.validate.nonEmptyTables)
                ? <span className="appForm__field--required">*</span> : null}
            </label>
            {rows
                ? <div style={{ width: '100%', overflow: 'auto' }}>
                    <RenderTable
                        columnsCfg={columns}
                        rowsData={rows}
                        lastRowCfg={lastRow}
                        setRowsFn={updateRows}
                        disabled={disabled}/>
                </div>
                : null}
            {!isEmpty(columns) && !shouldDisableNewRows
                ? <div className="addNewTableRow p-button p-component" onClick={addNewRow}>
                    {__('Aggiungi una riga', 'gepafin')}
                </div>
                : null}
        </>)
}

export default Table;