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

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

import { useState, useContext, useEffect } from "react"; //Классы React
import { BackEndCtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { NODE_TYPE } from "./common"; //Общие ресурсы и константы редактора

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

//Ширина элемента диаграммы
const NODE_WIDTH = 250;

//Высота единицы состава группового элемента диаграммы
const GROUP_NODE_ITEM_HEIGHT = 50;

//Стили
const STYLES = {
    ATTRIBUTE: isLast => ({ borderBottom: isLast ? "none" : "1px solid #dee2e6" })
};

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

//Конвертация серверного описания сущностей запроса в элементы диаграммы
const serverEntity2QueryDiagramNodes = entity => {
    //Ссылка на атрибуты
    const attrs = entity.attrs || [];
    //Количество атрибутов
    const attrsCount = attrs.length;
    //Высота группового элемента диаграммы
    const entityNodeHeight = GROUP_NODE_ITEM_HEIGHT + attrsCount * GROUP_NODE_ITEM_HEIGHT;
    //Элемент диаграммы для сущности (групповой элемент)
    const entityNode = {
        id: entity.id,
        type: NODE_TYPE.ENTITY,
        data: { ...entity },
        position: { x: entity.x, y: entity.y },
        style: {
            width: NODE_WIDTH,
            height: entityNodeHeight
        },
        draggable: true
    };
    //Элементы диаграммы для атрибутов сущности (состав группового элемента)
    const attrsNodes = attrs.map((attr, index, attrs) => ({
        id: attr.id,
        type: NODE_TYPE.ATTRIBUTE,
        data: { ...attr },
        position: { x: 1, y: GROUP_NODE_ITEM_HEIGHT * (index + 1) },
        parentId: entity.id,
        extent: "parent",
        style: {
            width: NODE_WIDTH - 2,
            height: GROUP_NODE_ITEM_HEIGHT,
            ...STYLES.ATTRIBUTE(index === attrs.length - 1)
        },
        draggable: false,
        selectable: true
    }));
    //Возвращаем элемент для сущности (групповой) и элементы для атрибутов (состав группового)
    return [entityNode, ...attrsNodes];
};

//Конвертация серверного описания запроса в данные для редактора диаграмм
const serverQueryData2QueryDiagram = (entities, relations) => {
    //Инициализация результата
    const result = { entities: [], relations: [], nodes: [], edges: [] };
    //Сущности (почти как есть на сервере, только массив XATTRS.XATTR перемещается в attrs)
    result.entities = entities.map(e => {
        const tmp = { ...e };
        tmp.attrs = tmp?.XATTRS?.XATTR?.map(a => ({ ...a })) || [];
        delete tmp.XATTRS;
        return tmp;
    });
    //Связи сущностей
    result.relations = relations.map(r => ({ ...r }));
    //Элементы для диаграммы
    result.entities.forEach(entity => {
        const nodes = serverEntity2QueryDiagramNodes(entity);
        result.nodes = [...result.nodes, ...nodes];
    });
    //Грани для диаграммы
    result.edges = relations.map(r => ({ ...r, animated: r.mandatory === 1 ? false : true }));
    //Вернем итоговый результат
    return result;
};

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

//Работа с метаданными запроса
const useQuery = query => {
    //Собственное состояние - флаг инициализированности
    const [isInit, setInit] = useState(false);

    //Собственное состояние - флаг загрузки
    const [isLoading, setLoading] = useState(false);

    //Собственное состояние - флаг необходимости обновления
    const [refresh, setRefresh] = useState(true);

    //Собственное состояние - данные диаграммы
    const [queryDiagram, setQueryDiagram] = useState(null);

    //Собственное состояние - данные настроек
    const [queryOption, setQueryOption] = useState(null);

    //Собственное состояние - данные SQL-запроса
    const [querySQL, setQuerySQL] = useState(null);

    //Подключение к контексту взаимодействия с сервером
    const { executeStored } = useContext(BackEndCtx);

    //Обновление данных
    const doRefresh = () => setRefresh(true);

    //При необходимости получить/обновить данные
    useEffect(() => {
        //Загрузка данных с сервера
        const loadData = async () => {
            try {
                setLoading(true);
                const data = await executeStored({
                    stored: "PKG_P8PANELS_QE.QUERY",
                    args: { NRN: query },
                    respArg: "COUT",
                    isArray: name => ["XENT", "XATTR", "XRL", "XARG"].includes(name),
                    attributeValueProcessor: (name, val) => (["value"].includes(name) ? undefined : val),
                    loader: true
                });
                setQueryDiagram(serverQueryData2QueryDiagram(data?.XENTS?.XENT || [], data?.XRLS?.XRL || []));
                setQueryOption({
                    args: data?.XOPT?.XARGS?.XARG || [],
                    cond: data?.XOPT?.XCOND || null,
                    substArgsVals: data?.XOPT?.XSUBST_ARGS_VALS || 0
                });
                setQuerySQL({ qry: data?.XQRY, qryBnd: data?.XQRY_BND, qryMsg: data?.XQRY_MSG });
                setInit(true);
            } finally {
                setRefresh(false);
                setLoading(false);
            }
        };
        //Если надо обновить
        if (refresh)
            if (query)
                //Если есть для чего получать данные
                loadData();
            //Нет идентификатора запроса - нет данных
            else {
                setQueryDiagram(null);
                setQueryOption(null);
                setQuerySQL(null);
            }
    }, [refresh, query, executeStored]);

    //При изменении входных свойств - поднимаем флаг обновления
    useEffect(() => setRefresh(true), [query]);

    //Возвращаем интерфейс хука
    return [queryDiagram, queryOption, querySQL, doRefresh, isLoading, isInit];
};

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

export { useQuery };
