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

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

import React, { useState, useContext } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Chip, Stack, TextField, Button, Icon } from "@mui/material"; //Интерфейсные элементы
import { P8PConfigDialog } from "../../components/editors/p8p_config_dialog"; //Диалог настройки
import { isElementNameCorrect } from "../../components/editors/p8p_editors_common"; //Общие ресурсы редакторов
import { P8PEditorSubHeader } from "../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
import { P8PEditorBox } from "../../components/editors/p8p_editor_box"; //Контейнер редактора
import { MessagingCtx } from "../../context/messaging"; //Контекст сообщений
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
import { STYLES as COMMON_STYLES } from "../../components/editors/p8p_editors_common"; //Общие ресурсы редакторов
import { P8PChipList } from "../../components/editors/p8p_chip_list"; //Дополнительные настройки редактора

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

//Стили
const STYLES = {
    STACK_DEPENENCIES: { gap: "5px", ...APP_STYLES.SCROLL, overflow: "auto", maxHeight: "160px", width: "260px" },
    CHIP_DEPENDENCY: { ...COMMON_STYLES.CHIP(true, false), minHeight: "32px" }
};

//Начальное состояние переменной
const VARIABLE_INITIAL = {
    dependencies: [],
    description: "",
    value: ""
};

//Структура переменной
export const VARIABLE_SHAPE = PropTypes.shape({
    dependencies: PropTypes.arrayOf(PropTypes.string),
    description: PropTypes.string.isRequired,
    value: PropTypes.string
});

//------------------------------------
//Вспомогательные функции и компоненты
//------------------------------------

//Редактор переменной
const VariableEditor = ({ variableName = "", variable = null, dependencies = [], onDependencyClick, onOk, onCancel } = {}) => {
    //Собственное состояние - имя переменной
    const [name, setName] = useState(variableName || "");

    //Собственное состояние - параметры переменной
    const [state, setState] = useState({ ...VARIABLE_INITIAL, ...variable });

    //При закрытии редактора с сохранением
    const handleOk = () => onOk(name, { ...state });

    //При закрытии редактора с отменой
    const handleCancel = () => onCancel();

    //При изменении параметра переменной
    const handleChange = e => {
        //Если это поле наименования, то проверяем корректность
        if (e.target.id === "name" && isElementNameCorrect(e.target.value)) setName(e.target.value);
        //Устанавливаем значение
        else setState(pv => ({ ...pv, [e.target.id]: e.target.value }));
    };

    //Доступность сохранения настроек элемента
    const okDisabled = !name || !state.description ? true : false;

    //Формирование представления
    return (
        <P8PConfigDialog title={`${variable ? "Изменение" : "Добавление"} элемента`} onOk={handleOk} onCancel={handleCancel} okDisabled={okDisabled}>
            <Stack direction={"column"} spacing={1}>
                <TextField type={"text"} variant={"standard"} value={name} label={"Имя"} id={"name"} onChange={handleChange} required={true} />
                <TextField
                    type={"text"}
                    variant={"standard"}
                    value={state.description}
                    label={"Описание"}
                    id={"description"}
                    onChange={handleChange}
                    required={true}
                />
            </Stack>
            {dependencies.length !== 0 ? (
                <>
                    <P8PEditorSubHeader title={"Зависимости"} />
                    <Stack sx={STYLES.STACK_DEPENENCIES} direction={"column"} p={1} useFlexGap={true}>
                        {dependencies.map((item, i) => (
                            <Chip
                                key={i}
                                label={item}
                                variant={"outlined"}
                                onClick={() => onDependencyClick && onDependencyClick(item)}
                                sx={STYLES.CHIP_DEPENDENCY}
                            />
                        ))}
                    </Stack>
                </>
            ) : null}
        </P8PConfigDialog>
    );
};

//Контроль свойств - редактор переменной
VariableEditor.propTypes = {
    variableName: PropTypes.string,
    variable: VARIABLE_SHAPE,
    dependencies: PropTypes.array,
    onDependencyClick: PropTypes.func.isRequired,
    onOk: PropTypes.func.isRequired,
    onCancel: PropTypes.func.isRequired
};

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

//Редактор глобальных свойств панели
const PanelPropsEditor = ({ valueProviders = {}, onSettingsChange, onDependencyClick } = {}) => {
    //Собственное состояние - редактор переменных панели
    const [variableEditor, setVariableEditor] = useState({ display: false, item: null });

    //Подключение к контексту сообщений
    const { showMsgErr } = useContext(MessagingCtx);

    //При добавлении новой переменной
    const handleVariableAdd = () => setVariableEditor({ display: true, item: null });

    //При нажатии на переменную
    const handleVariableClick = index => setVariableEditor({ display: true, item: variables[index] });

    //При отмене сохранения изменений переменной
    const handleVariableCancel = () => setVariableEditor({ display: false, index: null });

    //При сохранении изменений переменной
    const handleVariableSave = (variableName, variable) => {
        //Текст ошибки
        let msgError = "";
        //Если это добавление или изменилось наименование - проверяем на дублирование
        if ((!variableEditor.item || variableEditor.item !== variableName) && Object.prototype.hasOwnProperty.call(valueProviders, variableName)) {
            msgError = `Дублирование наименования параметра "${variableName}".`;
        }
        //Если это исправление наименования параметра, но он используется
        if (variableEditor.item && variableEditor.item !== variableName && valueProviders[variableEditor.item].dependencies.length !== 0) {
            msgError = `Переменная имеет связи с компонентами. Изменение наименования запрещено.`;
        }
        //Если есть ошибка - выводим
        if (msgError) {
            showMsgErr(msgError);
        } else {
            //Копируем параметры
            let newValueProviders = { ...valueProviders };
            //Удаляем старое значение, если требуется
            variableEditor.item && variableEditor.item !== variableName ? delete newValueProviders[variableEditor.item] : null;
            //Добавляем новый параметр
            newValueProviders = { ...newValueProviders, [variableName]: { ...variable } };
            //Обновляем проводники панели
            onSettingsChange({ valueProviders: { ...newValueProviders } });
            //Закрываем редактирование
            setVariableEditor({ display: false, index: null });
        }
    };

    //При удалении переменной
    const handleVariableDelete = index => {
        const variable = variables[index];
        //Если переменная не используется в компонентах - удаляем
        if (valueProviders[variable].dependencies.length === 0) {
            const newValueProviders = { ...valueProviders };
            delete newValueProviders[variable];
            onSettingsChange({ valueProviders: { ...newValueProviders } });
        } else {
            showMsgErr(`Переменная имеет связи с компонентами. Удаление запрещено.`);
        }
    };

    //При нажатии на зависимый компонент
    const handleDependencyClick = id => {
        //Закрываем редактирование
        setVariableEditor({ display: false, index: null });
        //Открываем настройку компонента
        onDependencyClick(id);
    };

    //Текущие переменные панели
    const variables = Object.keys(valueProviders).reduce((res, key) => [...res, key], []);

    //Определяем структуру переменных для отображения
    const variableChips = variables.map(item => ({ text: item, title: item }));

    //Формирование представления
    return (
        <P8PEditorBox title={"Параметры панели"}>
            {variableEditor.display && (
                <VariableEditor
                    variableName={variableEditor.item}
                    variable={variableEditor.item !== null ? { ...valueProviders[variableEditor.item] } : null}
                    dependencies={variableEditor.item ? valueProviders[variableEditor.item].dependencies : []}
                    onDependencyClick={handleDependencyClick}
                    onCancel={handleVariableCancel}
                    onOk={handleVariableSave}
                />
            )}
            <P8PEditorSubHeader title={"Переменные"} />
            <P8PChipList items={variableChips} onClick={handleVariableClick} onDelete={handleVariableDelete} />
            <Button startIcon={<Icon>add</Icon>} onClick={handleVariableAdd}>
                Добавить переменную
            </Button>
        </P8PEditorBox>
    );
};

//Контроль свойств компонента - редактор глобальных свойств панели
PanelPropsEditor.propTypes = {
    valueProviders: PropTypes.object,
    onSettingsChange: PropTypes.func.isRequired,
    onDependencyClick: PropTypes.func.isRequired
};

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

export { PanelPropsEditor };
