/*
    Парус 8 - Панели мониторинга - Редактор панелей
    Корневой компонент
*/

//---------------------
//Подключение библиотек
//---------------------

import React, { useEffect, useState, useContext } from "react"; //Классы React
import { Responsive, WidthProvider } from "react-grid-layout"; //Адаптивный макет
import { Box, Grid, Menu, MenuItem, Icon, Fab } from "@mui/material"; //Интерфейсные элементы
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Рабочая область приложения
import { P8PEditorToolBar } from "../../components/editors/p8p_editor_toolbar"; //Панель инструментов редактора
import { genGUID } from "../../core/utils"; //Общие вспомогательные функции
import { LayoutItem } from "./layout_item"; //Элемент макета
import { ComponentView } from "./component_view"; //Представление компонента панели
import { ComponentEditor } from "./component_editor"; //Редактор свойств компонента панели
import { COMPONETNS } from "./components/components"; //Описание доступных компонентов
import "react-grid-layout/css/styles.css"; //Стили для адаптивного макета
import "react-resizable/css/styles.css"; //Стили для адаптивного макета
import "./panels_editor.css"; //Стили редактора панелей

//---------
//Константы
//---------

//Стили
const STYLES = {
    CONTAINER: { display: "flex" },
    GRID_CONTAINER: { height: `calc(100vh - ${APP_BAR_HEIGHT})` },
    GRID_ITEM_INSPECTOR: { backgroundColor: "#e9ecef" },
    FAB_EDIT: { position: "absolute", top: 12, right: 12, zIndex: 2000 }
};

//Заголовоки по умолчанию
const PANEL_CAPTION_EDIT_MODE = "Редактор панелей";
const PANEL_CAPTION_EXECUTE_MODE = "Исполнение панели";

//Начальное состояние размера макета
const INITIAL_BREAKPOINT = "lg";

//Начальное состояние макета
const INITIAL_LAYOUTS = {
    [INITIAL_BREAKPOINT]: []
};

//-----------
//Тело модуля
//-----------

//Обёрдка для динамического макета
const ResponsiveGridLayout = WidthProvider(Responsive);

//Корневой компонент редактора панелей
const PanelsEditor = () => {
    //Собственное состояние
    const [components, setComponents] = useState({});
    const [valueProviders, setValueProviders] = useState({});
    const [layouts, setLayouts] = useState(INITIAL_LAYOUTS);
    const [breakpoint, setBreakpoint] = useState(INITIAL_BREAKPOINT);
    const [editMode, setEditMode] = useState(true);
    const [editComponent, setEditComponent] = useState(null);
    const [addMenuAnchorEl, setAddMenuAnchorEl] = useState(null);

    //Подключение к контексту приложения
    const { setAppBarTitle } = useContext(ApplicationСtx);

    //Добвление компонента в макет
    const addComponent = component => {
        const id = genGUID();
        setLayouts(pv => ({ ...pv, [breakpoint]: [...pv[breakpoint], { i: id, x: 0, y: 0, w: 4, h: 10 }] }));
        setComponents(pv => ({ ...pv, [id]: { ...component } }));
    };

    //Удаление компонента из макета
    const deleteComponent = id => {
        setLayouts(pv => ({ ...pv, [breakpoint]: layouts[breakpoint].filter(item => item.i !== id) }));
        setComponents(pv => ({ ...pv, [id]: { ...pv[id], deleted: true } }));
        if (valueProviders[id]) {
            const vPTmp = { ...valueProviders };
            delete vPTmp[id];
            setValueProviders(vPTmp);
        }
        editComponent === id && closeComponentSettingsEditor();
    };

    //Включение/выключение режима редиктирования
    const toggleEditMode = () => {
        if (!editMode) setAppBarTitle(PANEL_CAPTION_EDIT_MODE);
        else setAppBarTitle(PANEL_CAPTION_EXECUTE_MODE);
        setEditMode(!editMode);
    };

    //Открытие редактора настроек компонента
    const openComponentSettingsEditor = id => setEditComponent(id);

    //Закрытие реактора настроек компонента
    const closeComponentSettingsEditor = () => setEditComponent(null);

    //Открытие/сокрытие меню добавления
    const toggleAddMenu = target => setAddMenuAnchorEl(target instanceof Element ? target : null);

    //При изменении размера холста
    const handleBreakpointChange = breakpoint => setBreakpoint(breakpoint);

    //При изменении состояния макета
    const handleLayoutChange = (currentLayout, layouts) => setLayouts(layouts);

    //При нажатии на кнопку добалвения
    const handleAddClick = e => toggleAddMenu(e.currentTarget);

    //При выборе элемента меню добавления
    const handleAddMenuItemClick = component => {
        toggleAddMenu();
        addComponent(component);
    };

    //При изменении значений в компоненте
    const handleComponentValuesChange = (id, values) => setValueProviders(pv => ({ ...pv, [id]: { ...values } }));

    //При нажатии на настройки компонента
    const handleComponentSettingsClick = id => (editComponent === id ? closeComponentSettingsEditor() : openComponentSettingsEditor(id));

    //При изменении настроек компонента
    const handleComponentSettingsChange = ({ id = null, settings = {}, providedValues = [], closeEditor = false } = {}) => {
        if (id && components[id]) {
            const providedValuesInit = providedValues.reduce((res, providedValue) => ({ ...res, [providedValue]: undefined }), {});
            if (valueProviders[id]) {
                const vPTmp = { ...valueProviders[id] };
                Object.keys(valueProviders[id]).forEach(key => !providedValues.includes(key) && delete vPTmp[key]);
                setValueProviders(pv => ({ ...pv, [id]: { ...providedValuesInit, ...vPTmp } }));
            } else setValueProviders(pv => ({ ...pv, [id]: providedValuesInit }));
            setComponents(pv => ({ ...pv, [editComponent]: { ...pv[editComponent], settings: { ...settings } } }));
            if (closeEditor === true) closeComponentSettingsEditor();
        }
    };

    //При удалении компоненета
    const handleComponentDeleteClick = id => deleteComponent(id);

    //При подключении к странице
    useEffect(() => {
        //addComponent(COMPONETNS[0]);
        //addComponent(COMPONETNS[3]);
        //addComponent(COMPONETNS[4]);
        //addComponent(COMPONETNS[1]);
        //addComponent(COMPONETNS[2]);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    //Текущие значения панели
    const values = Object.keys(valueProviders).reduce((res, key) => ({ ...res, ...valueProviders[key] }), {});

    //Меню добавления
    const addMenu = (
        <Menu anchorEl={addMenuAnchorEl} open={Boolean(addMenuAnchorEl)} onClose={toggleAddMenu}>
            {COMPONETNS.map((comp, i) => (
                <MenuItem key={i} onClick={() => handleAddMenuItemClick(comp)}>
                    {comp.name}
                </MenuItem>
            ))}
        </Menu>
    );

    //Кнопка редактирования
    const editButton = !editMode && (
        <Fab sx={STYLES.FAB_EDIT} size={"small"} color={"grey.700"} title={"Редактировать"} onClick={toggleEditMode}>
            <Icon>edit</Icon>
        </Fab>
    );

    //Панель инструмментов
    const toolBar = (
        <P8PEditorToolBar
            items={[
                { icon: "play_arrow", title: "Запустить", onClick: toggleEditMode },
                {
                    icon: "add",
                    title: "Добавить элемент",
                    onClick: handleAddClick
                }
            ]}
        />
    );

    //Генерация содержимого
    return (
        <Box sx={STYLES.CONTAINER}>
            {editButton}
            {addMenu}
            <Grid container sx={STYLES.GRID_CONTAINER} columns={25}>
                <Grid item xs={editMode ? 20 : 25}>
                    <ResponsiveGridLayout
                        rowHeight={5}
                        className={"layout"}
                        layouts={layouts}
                        breakpoints={{ lg: 1200 }}
                        cols={{ lg: 12 }}
                        onBreakpointChange={handleBreakpointChange}
                        onLayoutChange={handleLayoutChange}
                        useCSSTransforms={true}
                        compactType={"vertical"}
                        isDraggable={editMode}
                        isResizable={editMode}
                    >
                        {layouts[breakpoint].map(item => (
                            <LayoutItem
                                key={item.i}
                                onSettingsClick={handleComponentSettingsClick}
                                onDeleteClick={handleComponentDeleteClick}
                                item={item}
                                editMode={editMode}
                                selected={editMode && editComponent === item.i}
                            >
                                <ComponentView
                                    id={item.i}
                                    path={components[item.i]?.path}
                                    settings={components[item.i]?.settings}
                                    values={values}
                                    onValuesChange={handleComponentValuesChange}
                                />
                            </LayoutItem>
                        ))}
                    </ResponsiveGridLayout>
                </Grid>
                {editMode && (
                    <Grid item xs={5} sx={STYLES.GRID_ITEM_INSPECTOR}>
                        {toolBar}
                        {editComponent && (
                            <>
                                <ComponentEditor
                                    id={editComponent}
                                    path={components[editComponent].path}
                                    settings={components[editComponent].settings}
                                    valueProviders={valueProviders}
                                    onSettingsChange={handleComponentSettingsChange}
                                />
                            </>
                        )}
                    </Grid>
                )}
            </Grid>
        </Box>
    );
};

//----------------
//Интерфейс модуля
//----------------

export { PanelsEditor };
