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

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

import { genUID } from "../../../core/utils"; //Вспомогательные функции
import {
    P8P_CA_DEF_TYPE_VALUE,
    P8P_CA_TYPE,
    P8P_CA_SOURCE_FIELDS,
    P8P_CA_OBJECT_SOURCE_FIELDS,
    P8P_CA_OPEN_UNIT_INITIAL,
    P8P_CA_INPUT_PARAM_INITIAL,
    P8P_CA_OPEN_PANEL_INITIAL,
    P8P_CA_VARIABLE_LINK_INITIAL
} from "./common"; //Общие ресурсы действий

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

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

//Доступность сохранения настроек действия
const isActionOkDisabled = action => {
    //Если область или тип не указаны
    if (!action.area || !action.type) return true;
    //Исходим от типа
    switch (action.type) {
        //Открыть раздел
        case P8P_CA_TYPE.openUnit.code:
            return !action.params.unitCode || !action.params.showMethod;
        //Открыть панель
        case P8P_CA_TYPE.openPanel.code:
            return !action.params.tabValue.type || !action.params.tabValue.value || !action.params.panelValue.type || !action.params.panelValue.value;
        //Установить переменную
        case P8P_CA_TYPE.setVariable.code:
            return action.params.length === 0 || action.params.some(item => !item.variableSource);
        //Для всех остальных
        default:
            return false;
    }
};

//Считывание параметров типа действия
const getActionTypeParams = type => {
    //Определяем от типа
    switch (type) {
        //Открыть раздел
        case P8P_CA_TYPE.openUnit.code:
            return { ...P8P_CA_OPEN_UNIT_INITIAL, inputParams: [{ ...P8P_CA_INPUT_PARAM_INITIAL }] };
        //Открыть панель
        case P8P_CA_TYPE.openPanel.code:
            return { ...P8P_CA_OPEN_PANEL_INITIAL };
        //Установить переменную
        case P8P_CA_TYPE.setVariable.code:
            return [{ ...P8P_CA_VARIABLE_LINK_INITIAL }];
        //Для всех остальных
        default:
            return {};
    }
};

//Определение значения действия по типу
const getActionValueByType = (type, value, values, prms = {}, getCustomTypeValue = null) => {
    //Исходим от типа действия
    switch (type) {
        //Значение (стандартное)
        case P8P_CA_DEF_TYPE_VALUE.TEXT_VALUE:
            return value;
        //Переменная (стандартное)
        case P8P_CA_DEF_TYPE_VALUE.VARIABLE:
            return values[value];
        //Кастомный тип
        default:
            return getCustomTypeValue ? getCustomTypeValue({ type, value, values, prms }) : null;
    }
};

//Определения функции действия
const getActionFunction = (item, onOpenUnit, configUrlBase, onOpenPanel, onProviderChange, getCustomTypeValue = null) => {
    //Выполняем исходя из типа действия
    switch (item.type) {
        //Открыть раздел
        case P8P_CA_TYPE.openUnit.code: {
            return ({ event, values, prms }) => {
                onOpenUnit({
                    unitCode: item.params.unitCode,
                    showMethod: item.params.showMethod,
                    inputParameters: item.params.inputParams.reduce(
                        (prev, cur) =>
                            cur.inputParameter
                                ? [
                                      ...prev,
                                      {
                                          name: cur.inputParameter,
                                          value: getActionValueByType(cur.resultValue.type, cur.resultValue.value, values, prms, getCustomTypeValue)
                                      }
                                  ]
                                : [...prev],
                        []
                    ),
                    modal: item.params.modal
                });
                event?.stopPropagation && event.stopPropagation();
            };
        }
        //Открыть панель
        case P8P_CA_TYPE.openPanel.code: {
            return ({ event, values, prms }) => {
                onOpenPanel({
                    id: genUID(),
                    url: `${configUrlBase}panels_editor?SCODE=${getActionValueByType(
                        item.params.panelValue.type,
                        item.params.panelValue.value,
                        values,
                        prms,
                        getCustomTypeValue
                    )}`,
                    caption:
                        getActionValueByType(item.params.tabValue.type, item.params.tabValue.value, values, prms, getCustomTypeValue) ||
                        "Редактор панелей"
                });
                event?.stopPropagation && event.stopPropagation();
            };
        }
        //Установить переменную
        case P8P_CA_TYPE.setVariable.code: {
            //Устанавливаем новые значения проводников
            return ({ event, values, prms }) => {
                //Собираем объект новых значений проводников
                let changedValues = item.params.reduce(
                    (prev, cur) => ({
                        ...prev,
                        ...{
                            [cur.variableSource]: getActionValueByType(cur.resultValue.type, cur.resultValue.value, values, prms, getCustomTypeValue)
                        }
                    }),
                    {}
                );
                onProviderChange({ ...changedValues });
                event?.stopPropagation && event.stopPropagation();
            };
        }
    }
};

//Выполнение действий компонента
const getHandlersByActions = (actions, onOpenUnit, configUrlBase, onOpenPanel, onProviderChange, getCustomTypeValue = null) => {
    //Инициализируем обработчики
    const handlers = actions.reduce((prev, cur) => {
        //Ключ обработчика
        let key = `${cur.area}.${cur.element}`;
        //Если уже был добавлен - не добавляем, иначе добавляем
        return !prev[key] ? { ...prev, [key]: { area: cur.area, element: cur.element, fn: null } } : { ...prev };
    }, {});
    //Обходим уникальные обработчики
    for (const handler in handlers) {
        //Считываем действия области
        let areaActions = actions.filter(item => item.area === handlers[handler].area && item.element === handlers[handler].element);
        //Собираем массив обработчиков области
        let areaFunctions = areaActions.reduce(
            (fns, action) => [...fns, getActionFunction(action, onOpenUnit, configUrlBase, onOpenPanel, onProviderChange, getCustomTypeValue)],
            []
        );
        //Устанавливаем области последовательный вызов обработчиков
        handlers[handler].fn = ({ event, values, prms }) => {
            areaFunctions.map(fn => fn({ event, values, prms }));
        };
    }
    //Возвращаем обработчики
    return handlers;
};

//Считывание всех связанных переменных рекурсивно
const getActionsVariablesRecursive = (objValue, propName = null) => {
    //Если это значение
    if (!(typeof objValue === "object") && !Array.isArray(objValue)) {
        //Если поле из списка хранящих ссылку - берем его
        return P8P_CA_SOURCE_FIELDS.includes(propName) && objValue ? [objValue] : [];
    }
    //Если это объект хранящий тип и значение - может хранить ссылку на переменную
    if (P8P_CA_OBJECT_SOURCE_FIELDS.includes(propName)) {
        //Если тип "Переменная" - указываем значение
        return objValue?.type === P8P_CA_DEF_TYPE_VALUE.VARIABLE && objValue?.value ? [objValue.value] : [];
    }
    //Если это массив
    if (Array.isArray(objValue)) {
        return objValue.reduce((prev, cur) => [...prev, ...getActionsVariablesRecursive(cur)], []);
    } else {
        //Если это объект
        return Object.keys(objValue).reduce((prev, cur) => [...prev, ...getActionsVariablesRecursive(objValue[cur], cur)], []);
    }
};

//Считывание всех связанных переменных действий
const getActionsVariables = actions => {
    //Считываем связанные переменные действий рекурсивно
    return getActionsVariablesRecursive(actions);
};

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

export { isActionOkDisabled, getActionTypeParams, getActionsVariables, getHandlersByActions };
