/*
    Парус 8 - Панели мониторинга
    Компонент: Таблица
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useEffect, useState, useMemo } 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 { P8PAppInlineError } from "./p8p_app_message"; //Встраиваемое сообщение об ошибке
//---------
//Константы
//---------
//Размеры отступов
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"
};
//Действия меню столбца
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 STYLES = {
    TABLE: {
        with: "100%"
    },
    TABLE_ROW: {
        "&:last-child td, &:last-child th": { border: 0 }
    },
    TABLE_CELL_EXPAND_CONTAINER: {
        paddingBottom: 0,
        paddingTop: 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 hasValue = value => typeof value !== "undefined" && value !== null && value !== "";
//Панель инструментов столбца
const P8PTableColumnToolBar = ({ 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}
        >
    );
};
//Контроль свойств - Панель инструментов столбца
P8PTableColumnToolBar.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 P8PTableColumnHintDialog = ({ columnDef, okBtnCaption, onOk }) => {
    return (
        
    );
};
//Контроль свойств - Диалог подсказки
P8PTableColumnHintDialog.propTypes = {
    columnDef: PropTypes.object.isRequired,
    okBtnCaption: PropTypes.string.isRequired,
    onOk: 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 = ({
    columnsDef,
    rows,
    orders,
    filters,
    size,
    morePages,
    reloading,
    expandable,
    orderAscMenuItemCaption,
    orderDescMenuItemCaption,
    filterMenuItemCaption,
    valueFilterCaption,
    valueFromFilterCaption,
    valueToFilterCaption,
    okFilterBtnCaption,
    clearFilterBtnCaption,
    cancelFilterBtnCaption,
    morePagesBtnCaption,
    noDataFoundText,
    headCellRender,
    dataCellRender,
    rowExpandRender,
    valueFormatter,
    onOrderChanged,
    onFilterChanged,
    onPagesCountChanged
}) => {
    //Собственное состояние - фильтруемая колонка
    const [filterColumn, setFilterColumn] = useState(null);
    //Собственное состояние - развёрнутые строки
    const [expanded, setExpanded] = useState({});
    //Собственное состояние - колонка с отображаемой подсказкой
    const [displayHintColumn, setDisplayHintColumn] = useState(null);
    //Описание фильтруемой колонки
    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 visibleColumns = useMemo(() => columnsDef.filter(columnDef => columnDef.visible === true), [columnsDef]);
    //Определение количества видимых колонок
    const visibleColumnsCount = useMemo(() => visibleColumns.length + (expandable === true ? 1 : 0), [visibleColumns, expandable]);
    //Выравнивание в зависимости от типа данных
    const getAlignByDataType = dataType =>
        dataType === P8P_TABLE_DATA_TYPE.DATE ? "center" : dataType === P8P_TABLE_DATA_TYPE.NUMB ? "right" : "left";
    //Упорядочение содержимого в зависимости от типа данных
    const getJustifyContentByDataType = dataType =>
        dataType === P8P_TABLE_DATA_TYPE.DATE ? "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;
        }
    };
    //Отработка нажатия на пункты меню
    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]);
    //Генерация содержимого
    return (
        <>
            {displayHintColumn ? (
                
            ) : null}
            {filterColumn ? (
                
            ) : null}
            {Array.isArray(filters) && filters.length > 0 ? (
                
            ) : null}
            
                
                    
                        
                            {expandable && rowExpandRender ?  : null}
                            {visibleColumns.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
                            ? rows.map((row, i) => (
                                  
                                      
                                          {expandable && rowExpandRender ? (
                                              
                                                   handleExpandClick(i)}>
                                                      {expanded[i] === true ? "keyboard_arrow_down" : "keyboard_arrow_right"}
                                                  
                                              
                                          ) : null}
                                          {visibleColumns.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}
                    
                
                {rows.length == 0 ? (
                    noDataFoundText && !reloading ? (
                        
                    ) : null
                ) : morePages ? (
                    
                        
                    
                ) : null}
            
        >
    );
};
//Контроль свойств - Таблица
P8PTable.propTypes = {
    columnsDef: PropTypes.arrayOf(
        PropTypes.shape({
            name: PropTypes.string.isRequired,
            caption: PropTypes.string.isRequired,
            order: PropTypes.bool.isRequired,
            filter: PropTypes.bool.isRequired,
            dataType: PropTypes.string.isRequired,
            values: PropTypes.array
        })
    ).isRequired,
    rows: PropTypes.array.isRequired,
    orders: PropTypes.arrayOf(
        PropTypes.shape({
            name: PropTypes.string.isRequired,
            direction: PropTypes.string.isRequired
        })
    ).isRequired,
    filters: PropTypes.arrayOf(P8P_TABLE_FILTER_SHAPE).isRequired,
    size: PropTypes.string,
    morePages: PropTypes.bool.isRequired,
    reloading: PropTypes.bool.isRequired,
    expandable: PropTypes.bool,
    orderAscMenuItemCaption: PropTypes.string.isRequired,
    orderDescMenuItemCaption: PropTypes.string.isRequired,
    filterMenuItemCaption: PropTypes.string.isRequired,
    valueFilterCaption: PropTypes.string.isRequired,
    valueFromFilterCaption: PropTypes.string.isRequired,
    valueToFilterCaption: PropTypes.string.isRequired,
    okFilterBtnCaption: PropTypes.string.isRequired,
    clearFilterBtnCaption: PropTypes.string.isRequired,
    cancelFilterBtnCaption: PropTypes.string.isRequired,
    morePagesBtnCaption: PropTypes.string.isRequired,
    noDataFoundText: PropTypes.string,
    headCellRender: PropTypes.func,
    dataCellRender: PropTypes.func,
    rowExpandRender: PropTypes.func,
    valueFormatter: PropTypes.func,
    onOrderChanged: PropTypes.func,
    onFilterChanged: PropTypes.func,
    onPagesCountChanged: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
export { P8P_TABLE_DATA_TYPE, P8P_TABLE_SIZE, P8P_TABLE_FILTER_SHAPE, P8PTable };