/*
    Парус 8 - Панели мониторинга
    Компонент: Таблица
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useEffect, useState, useReducer } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import {
    Table,
    TableBody,
    TableCell,
    TableContainer,
    TableHead,
    TableRow,
    Paper,
    IconButton,
    Icon,
    Menu,
    MenuItem,
    Divider,
    Stack,
    Dialog,
    DialogTitle,
    DialogContent,
    DialogActions,
    Button,
    TextField,
    Chip,
    Container,
    Link
} from "@mui/material"; //Интерфейсные компоненты
import { useTheme } from "@mui/material/styles"; //Взаимодействие со стилями MUI
import { P8PAppInlineError, P8PHintDialog } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
import { P8P_TABLE_AT, HEADER_INITIAL_STATE, hasValue, p8pTableReducer } from "./p8p_table_reducer"; //Редьюсер состояния
//---------
//Константы
//---------
//Размеры отступов
const P8P_TABLE_SIZE = {
    SMALL: "small",
    MEDIUM: "medium"
};
//Типы данных
const P8P_TABLE_DATA_TYPE = {
    STR: "STR",
    NUMB: "NUMB",
    DATE: "DATE"
};
//Направления сортировки
const P8P_TABLE_COLUMN_ORDER_DIRECTIONS = {
    ASC: "ASC",
    DESC: "DESC"
};
//Действия панели инструментов столбца
const P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS = {
    ORDER_TOGGLE: "ORDER_TOGGLE",
    FILTER_TOGGLE: "FILTER_TOGGLE",
    EXPAND_TOGGLE: "EXPAND_TOGGLE"
};
//Действия меню столбца
const P8P_TABLE_COLUMN_MENU_ACTIONS = {
    ORDER_ASC: "ORDER_ASC",
    ORDER_DESC: "ORDER_DESC",
    FILTER: "FILTER"
};
//Структура элемента описания фильтра
const P8P_TABLE_FILTER_SHAPE = PropTypes.shape({
    name: PropTypes.string.isRequired,
    from: PropTypes.any,
    to: PropTypes.any
});
//Высота кнопки догрузки данных
const P8P_TABLE_MORE_HEIGHT = "49px";
//Высота фильтров таблицы
const P8P_TABLE_FILTERS_HEIGHT = "48px";
//Стили
const STYLES = {
    TABLE: {},
    TABLE_HEAD_STICKY: {
        position: "sticky",
        top: 0,
        zIndex: 1000
    },
    TABLE_HEAD_CELL_STICKY: (theme, left) => ({
        position: "sticky",
        left,
        backgroundColor: theme.palette.background.default,
        zIndex: 1000
    }),
    TABLE_ROW: {
        "&:last-child td, &:last-child th": { border: 0 }
    },
    TABLE_CELL_STICKY: (theme, left) => ({
        position: "sticky",
        left,
        backgroundColor: theme.palette.background.default,
        zIndex: 500
    }),
    TABLE_CELL_EXPAND_CONTROL: {
        minWidth: "60px",
        maxWidth: "60px"
    },
    TABLE_CELL_EXPAND_CONTAINER: {
        paddingBottom: 0,
        paddingTop: 0,
        paddingLeft: 0,
        paddingRight: 0
    },
    TABLE_CELL_GROUP_HEADER: {
        backgroundColor: "lightgray"
    },
    TABLE_CELL_GROUP_HEADER_STICKY: {
        position: "sticky",
        left: 0
    },
    TABLE_COLUMN_STACK: {
        alignItems: "center"
    },
    TABLE_COLUMN_MENU_ITEM_ICON: {
        paddingRight: "10px"
    },
    FILTER_CHIP: {
        alignItems: "center"
    },
    MORE_BUTTON_CONTAINER: {
        with: "100%",
        textAlign: "center",
        padding: "5px"
    }
};
//--------------------------------
//Вспомогательные классы и функции
//--------------------------------
//Панель инструментов столбца (левая)
const P8PTableColumnToolBarLeft = ({ columnDef, onItemClick }) => {
    //Кнопка развёртывания/свёртывания
    let expButton = null;
    if (columnDef.expandable)
        expButton = (
             (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.EXPAND_TOGGLE, columnDef.name) : null)}>
                {columnDef.expanded ? "indeterminate_check_box" : "add_box"}
            
        );
    //Генерация содержимого
    return <>{expButton}>;
};
//Контроль свойств - Панель инструментов столбца (левая)
P8PTableColumnToolBarLeft.propTypes = {
    columnDef: PropTypes.object.isRequired,
    onItemClick: PropTypes.func
};
//Панель инструментов столбца (правая)
const P8PTableColumnToolBarRight = ({ columnDef, orders, filters, onItemClick }) => {
    //Кнопка сортировки
    const order = orders.find(o => o.name == columnDef.name);
    let orderButton = null;
    if (order)
        orderButton = (
             (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.ORDER_TOGGLE, columnDef.name) : null)}>
                {order.direction === P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC ? "arrow_upward" : "arrow_downward"}
            
        );
    //Кнопка фильтрации
    const filter = filters.find(f => f.name == columnDef.name);
    let filterButton = null;
    if (hasValue(filter?.from) || hasValue(filter?.to))
        filterButton = (
             (onItemClick ? onItemClick(P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.FILTER_TOGGLE, columnDef.name) : null)}>
                filter_alt
            
        );
    //Генерация содержимого
    return (
        <>
            {orderButton}
            {filterButton}
        >
    );
};
//Контроль свойств - Панель инструментов столбца (правая)
P8PTableColumnToolBarRight.propTypes = {
    columnDef: PropTypes.object.isRequired,
    orders: PropTypes.array.isRequired,
    filters: PropTypes.array.isRequired,
    onItemClick: PropTypes.func
};
//Меню столбца
const P8PTableColumnMenu = ({ columnDef, orderAscItemCaption, orderDescItemCaption, filterItemCaption, onItemClick }) => {
    //Собственное состояние
    const [anchorEl, setAnchorEl] = useState(null);
    //Флаг отображения
    const open = Boolean(anchorEl);
    //По нажатию на открытие меню
    const handleMenuButtonClick = event => {
        setAnchorEl(event.currentTarget);
    };
    //По нажатию на пункт меню
    const handleMenuItemClick = (event, index, action, columnName) => {
        if (onItemClick) onItemClick(action, columnName);
        setAnchorEl(null);
    };
    //При закрытии меню
    const handleMenuClose = () => {
        setAnchorEl(null);
    };
    //Формирование списка элементов меню в зависимости от описания колонки таблицы
    const menuItems = [];
    if (columnDef.order === true) {
        menuItems.push(
            
        );
        menuItems.push(
            
        );
    }
    if (columnDef.filter === true) {
        if (menuItems.length > 0) menuItems.push();
        menuItems.push(
            
        );
    }
    //Генерация содержимого
    return menuItems.length > 0 ? (
        <>
            
                more_vert
            
            
        >
    ) : null;
};
//Контроль свойств - Меню столбца
P8PTableColumnMenu.propTypes = {
    columnDef: PropTypes.object.isRequired,
    orderAscItemCaption: PropTypes.string.isRequired,
    orderDescItemCaption: PropTypes.string.isRequired,
    filterItemCaption: PropTypes.string.isRequired,
    onItemClick: PropTypes.func
};
//Диалог фильтра
const P8PTableColumnFilterDialog = ({
    columnDef,
    from,
    to,
    valueCaption,
    valueFromCaption,
    valueToCaption,
    okBtnCaption,
    clearBtnCaption,
    cancelBtnCaption,
    valueFormatter,
    onOk,
    onClear,
    onCancel
}) => {
    //Собственное состояние - значения с-по
    const [filterValues, setFilterValues] = useState({ from, to });
    //Отработка воода значения в фильтр
    const handleFilterTextFieldChanged = e => {
        setFilterValues(prev => ({ ...prev, [e.target.name]: e.target.value }));
    };
    //Элементы ввода значений фильтра
    let inputs = null;
    if (Array.isArray(columnDef.values) && columnDef.values.length > 0) {
        inputs = (
            
                {columnDef.values.map((v, i) => (
                    
                ))}
            
        );
    } else {
        switch (columnDef.dataType) {
            case P8P_TABLE_DATA_TYPE.STR: {
                inputs = (
                    
                );
                break;
            }
            case P8P_TABLE_DATA_TYPE.NUMB:
            case P8P_TABLE_DATA_TYPE.DATE: {
                inputs = (
                    <>
                        
                         
                        
                    >
                );
                break;
            }
        }
    }
    return (
        
    );
};
//Контроль свойств - Диалог фильтра
P8PTableColumnFilterDialog.propTypes = {
    columnDef: PropTypes.object.isRequired,
    from: PropTypes.any,
    to: PropTypes.any,
    valueCaption: PropTypes.string.isRequired,
    valueFromCaption: PropTypes.string.isRequired,
    valueToCaption: PropTypes.string.isRequired,
    okBtnCaption: PropTypes.string.isRequired,
    clearBtnCaption: PropTypes.string.isRequired,
    cancelBtnCaption: PropTypes.string.isRequired,
    valueFormatter: PropTypes.func,
    onOk: PropTypes.func,
    onClear: PropTypes.func,
    onCancel: PropTypes.func
};
//Сводный фильтр
const P8PTableFiltersChips = ({ filters, columnsDef, valueFromCaption, valueToCaption, onFilterChipClick, onFilterChipDelete, valueFormatter }) => {
    return (
        
            {filters.map((filter, i) => {
                const columnDef = columnsDef.find(columnDef => columnDef.name == filter.name);
                return (
                    
                                {columnDef.caption}: 
                                {hasValue(filter.from) && !columnDef.values && columnDef.dataType != P8P_TABLE_DATA_TYPE.STR
                                    ? `${valueFromCaption.toLowerCase()} `
                                    : null}
                                {hasValue(filter.from) ? (valueFormatter ? valueFormatter({ value: filter.from, columnDef }) : filter.from) : null}
                                {hasValue(filter.to) && !columnDef.values && columnDef.dataType != P8P_TABLE_DATA_TYPE.STR
                                    ? ` ${valueToCaption.toLowerCase()} `
                                    : null}
                                {hasValue(filter.to) ? (valueFormatter ? valueFormatter({ value: filter.to, columnDef }) : filter.to) : null}
                            
                        }
                        variant="outlined"
                        onClick={() => (onFilterChipClick ? onFilterChipClick(columnDef.name) : null)}
                        onDelete={() => (onFilterChipDelete ? onFilterChipDelete(columnDef.name) : null)}
                    />
                );
            })}
        
    );
};
//Контроль свойств - Сводный фильтр
P8PTableFiltersChips.propTypes = {
    filters: PropTypes.array.isRequired,
    columnsDef: PropTypes.array.isRequired,
    valueFromCaption: PropTypes.string.isRequired,
    valueToCaption: PropTypes.string.isRequired,
    onFilterChipClick: PropTypes.func,
    onFilterChipDelete: PropTypes.func,
    valueFormatter: PropTypes.func
};
//-----------
//Тело модуля
//-----------
//Таблица
const P8PTable = ({
    style = {},
    tableStyle = {},
    columnsDef = [],
    groups = [],
    rows = [],
    orders,
    filters,
    size,
    fixedHeader = false,
    fixedColumns = 0,
    morePages = false,
    reloading = false,
    expandable,
    orderAscMenuItemCaption,
    orderDescMenuItemCaption,
    filterMenuItemCaption,
    valueFilterCaption,
    valueFromFilterCaption,
    valueToFilterCaption,
    okFilterBtnCaption,
    clearFilterBtnCaption,
    cancelFilterBtnCaption,
    morePagesBtnCaption,
    morePagesBtnProps,
    noDataFoundText,
    headCellRender,
    dataCellRender,
    groupCellRender,
    rowExpandRender,
    valueFormatter,
    onOrderChanged,
    onFilterChanged,
    onPagesCountChanged,
    objectsCopier,
    containerComponent,
    containerComponentProps
}) => {
    //Собственное состояние - описание заголовка
    const [header, dispatchHeaderAction] = useReducer(p8pTableReducer, HEADER_INITIAL_STATE());
    //Собственное состояние - фильтруемая колонка
    const [filterColumn, setFilterColumn] = useState(null);
    //Собственное состояние - развёрнутые строки
    const [expanded, setExpanded] = useState({});
    //Собственное состояния - развёрнутые группы
    const [expandedGroups, setExpandedGroups] = useState(
        Array.isArray(groups) && groups.length > 0 ? Object.assign({}, ...groups.map(g => ({ [g.name]: g.expanded }))) : {}
    );
    //Собственное состояние - колонка с отображаемой подсказкой
    const [displayHintColumn, setDisplayHintColumn] = useState(null);
    //Стили
    const theme = useTheme();
    //Описание фильтруемой колонки
    const filterColumnDef = filterColumn ? columnsDef.find(columnDef => columnDef.name == filterColumn) || null : null;
    //Описание колонки с отображаемой подсказкой
    const displayHintColumnDef = displayHintColumn ? columnsDef.find(columnDef => columnDef.name == displayHintColumn) || null : null;
    //Значения фильтра фильтруемой колонки
    const [filterColumnFrom, filterColumnTo] = filterColumn
        ? (() => {
              const filter = filters.find(filter => filter.name == filterColumn);
              return filter ? [filter.from == null ? "" : filter.from, filter.to == null ? "" : filter.to] : ["", ""];
          })()
        : ["", ""];
    //Формирование заголовка таблицы
    const setHeader = ({ columnsDef, expandable, fixedColumns, objectsCopier }) =>
        dispatchHeaderAction({ type: P8P_TABLE_AT.SET_HEADER, payload: { columnsDef, expandable, fixedColumns, objectsCopier } });
    //Сворачивание/разворачивание уровня заголовка таблицы
    const toggleHeaderExpand = ({ columnName, objectsCopier }) =>
        dispatchHeaderAction({ type: P8P_TABLE_AT.TOGGLE_HEADER_EXPAND, payload: { columnName, expandable, fixedColumns, objectsCopier } });
    //Выравнивание в зависимости от типа данных
    const getAlignByDataType = ({ dataType, hasChild }) =>
        dataType === P8P_TABLE_DATA_TYPE.DATE || hasChild ? "center" : dataType === P8P_TABLE_DATA_TYPE.NUMB ? "right" : "left";
    //Упорядочение содержимого в зависимости от типа данных
    const getJustifyContentByDataType = ({ dataType, hasChild }) =>
        dataType === P8P_TABLE_DATA_TYPE.DATE || hasChild ? "center" : dataType === P8P_TABLE_DATA_TYPE.NUMB ? "flex-end" : "flex-start";
    //Отработка нажатия на элемент пункта меню
    const handleToolBarItemClick = (action, columnName) => {
        switch (action) {
            case P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.ORDER_TOGGLE: {
                const colOrder = orders.find(o => o.name == columnName);
                const newDirection =
                    colOrder?.direction == P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC
                        ? P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC
                        : colOrder?.direction == P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC
                        ? null
                        : P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC;
                if (onOrderChanged) onOrderChanged({ columnName, direction: newDirection });
                break;
            }
            case P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.FILTER_TOGGLE:
                setFilterColumn(columnName);
                break;
            case P8P_TABLE_COLUMN_TOOL_BAR_ACTIONS.EXPAND_TOGGLE:
                toggleHeaderExpand({ columnName, objectsCopier });
                break;
        }
    };
    //Отработка нажатия на пункты меню
    const handleMenuItemClick = (action, columnName) => {
        switch (action) {
            case P8P_TABLE_COLUMN_MENU_ACTIONS.ORDER_ASC:
                onOrderChanged({ columnName, direction: P8P_TABLE_COLUMN_ORDER_DIRECTIONS.ASC });
                break;
            case P8P_TABLE_COLUMN_MENU_ACTIONS.ORDER_DESC:
                onOrderChanged({ columnName, direction: P8P_TABLE_COLUMN_ORDER_DIRECTIONS.DESC });
                break;
            case P8P_TABLE_COLUMN_MENU_ACTIONS.FILTER:
                setFilterColumn(columnName);
                break;
        }
    };
    //Отработка ввода значения фильтра колонки
    const handleFilterOk = (columnName, from, to) => {
        if (onFilterChanged) onFilterChanged({ columnName, from: from === "" ? null : from, to: to === "" ? null : to });
        setFilterColumn(null);
    };
    //Отработка очистки значения фильтра колонки
    const handleFilterClear = columnName => {
        if (onFilterChanged) onFilterChanged({ columnName, from: null, to: null });
        setFilterColumn(null);
    };
    //Отработка отмены ввода значения фильтра колонки
    const handleFilterCancel = () => {
        setFilterColumn(null);
    };
    //Отработка нажатия на элемент сводного фильтра
    const handleFilterChipClick = columnName => setFilterColumn(columnName);
    //Отработка удаления элемента сводного фильтра
    const handleFilterChipDelete = columnName => (onFilterChanged ? onFilterChanged({ columnName, from: null, to: null }) : null);
    //Отработка нажатия на кнопку догрузки страницы
    const handleMorePagesBtnClick = () => {
        if (onPagesCountChanged) onPagesCountChanged();
    };
    //Отработка нажатия на элемент отображения подсказки по колонке
    const handleColumnShowHintClick = columnName => setDisplayHintColumn(columnName);
    //Отработка сокрытия подсказки по колонке
    const handleHintOk = () => setDisplayHintColumn(null);
    //Отработка нажатия на кнопку раскрытия элемента
    const handleExpandClick = rowIndex => {
        if (expanded[rowIndex] === true)
            setExpanded(pv => {
                let res = { ...pv };
                delete res[rowIndex];
                return res;
            });
        else setExpanded(pv => ({ ...pv, [rowIndex]: true }));
    };
    //При перезагрузке данных
    useEffect(() => {
        if (reloading) setExpanded({});
    }, [reloading]);
    //При изменении описания колонок
    useEffect(() => {
        setHeader({ columnsDef, expandable, fixedColumns, objectsCopier });
    }, [columnsDef, expandable, fixedColumns, objectsCopier]);
    //Генерация заголовка группы
    const renderGroupCell = group => {
        let customRender = {};
        if (groupCellRender) customRender = groupCellRender({ columnsDef: header.columnsDef, group }) || {};
        return header.displayDataColumns.map((columnDef, i) => (
            
                {i == 0 ? (
                    
                        {group.expandable ? (
                             {
                                    setExpandedGroups(pv => ({ ...pv, ...{ [group.name]: !pv[group.name] } }));
                                }}
                            >
                                {expandedGroups[group.name] ? "indeterminate_check_box" : "add_box"}
                            
                        ) : null}
                        {customRender.data ? customRender.data : group.caption}
                    
                ) : null}
            
        ));
    };
    //Генерация содержимого
    return (
        
            {displayHintColumn ? 
 : null}
            {filterColumn ? (
                
            ) : null}
            {Array.isArray(filters) && filters.length > 0 ? (
                
            ) : null}
            
                
                    
                        {header.displayLevels.map((level, i) => (
                            
                                {expandable && rowExpandRender && i == 0 ? (
                                    
                                ) : null}
                                {header.displayLevelsColumns[level].map((columnDef, j) => {
                                    let customRender = {};
                                    if (headCellRender) customRender = headCellRender({ columnDef }) || {};
                                    return (
                                        
                                            
                                                
                                                {customRender.data ? (
                                                    customRender.data
                                                ) : columnDef.hint ? (
                                                     handleColumnShowHintClick(columnDef.name)}
                                                    >
                                                        {columnDef.caption}
                                                    
                                                ) : (
                                                    columnDef.caption
                                                )}
                                                
                                                
                                            
                                        
                                    );
                                })}
                            
                        ))}
                    
                    
                        {rows.length > 0 ? (
                            (Array.isArray(groups) && groups.length > 0 ? groups : [{}]).map((group, g) => {
                                const rowsView = rows.map((row, i) =>
                                    !group?.name || group?.name == row.groupName ? (
                                        
                                            
                                                {expandable && rowExpandRender ? (
                                                    
                                                         handleExpandClick(i)}>
                                                            {expanded[i] === true ? "keyboard_arrow_down" : "keyboard_arrow_right"}
                                                        
                                                    
                                                ) : null}
                                                {header.displayDataColumns.map((columnDef, j) => {
                                                    let customRender = {};
                                                    if (dataCellRender) customRender = dataCellRender({ row, columnDef }) || {};
                                                    return (
                                                        
                                                            {customRender.data
                                                                ? customRender.data
                                                                : valueFormatter
                                                                ? valueFormatter({ value: row[columnDef.name], columnDef })
                                                                : row[columnDef.name]}
                                                        
                                                    );
                                                })}
                                            
                                            {expandable && rowExpandRender && expanded[i] === true ? (
                                                
                                                    
                                                        {rowExpandRender({ columnsDef, row })}
                                                    
                                                
                                            ) : null}
                                        
                                    ) : null
                                );
                                return !group?.name ? (
                                    rowsView
                                ) : (
                                    
                                        {renderGroupCell(group)}
                                        {!group.expandable || expandedGroups[group.name] === true ? rowsView : null}
                                    
                                );
                            })
                        ) : noDataFoundText && !reloading ? (
                            
                                
                                    
                                
                            
                        ) : null}
                    
                
            
            {morePages ? (
                
                    
                
            ) : null}