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

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

import { useRef, useContext, useCallback, useEffect, useState } from "react"; //Классы React
import { BackEndCtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
import { object2Base64XML } from "../../../../core/utils"; //Вспомогательные функции

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

//Работа с сущностями системы
const useEntities = (filter, minFilterLen) => {
    //Контроллер для прерывания запросов
    const abortController = useRef(null);

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

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

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

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

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

    //При необходимости получить/обновить данные
    useEffect(() => {
        //Загрузка данных с сервера
        const loadData = async () => {
            try {
                setLoading(true);
                abortController.current?.abort?.();
                abortController.current = new AbortController();
                const data = await executeStored({
                    stored: "PKG_P8PANELS_QE.ENTITY_LIST",
                    args: { SSEARCH: filter },
                    respArg: "COUT",
                    isArray: name => ["XENT"].includes(name),
                    attributeValueProcessor: (name, val) => (["name", "title"].includes(name) ? undefined : val),
                    loader: false,
                    signal: abortController.current.signal
                });
                setData(data?.XENTS?.XENT || null);
            } finally {
                setRefresh(false);
                setLoading(false);
            }
        };
        //Если надо обновить
        if (refresh) {
            //Если фильтр задан и он нас удовлетворяет  - получим данные
            if (filter && String(filter).length >= minFilterLen) loadData();
            //Нет фильтра - нет данных
            else {
                setData(null);
            }
        }
        //Сбрасываем запрос при смене зависимостей или отмонтировании
        return () => abortController.current?.abort?.();
    }, [refresh, filter, minFilterLen, executeStored]);

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

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

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

    //Добавление сущности в запрос
    const addEnt = useCallback(
        async (name, type) => {
            await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_ADD", args: { NRN: query, SNAME: name, STYPE: type }, loader: false });
        },
        [query, executeStored]
    );

    //Удаление сущности из запроса
    const removeEnt = useCallback(
        async ent => {
            await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_REMOVE", args: { NRN: query, SID: ent }, loader: false });
        },
        [query, executeStored]
    );

    //Сохранение координат сущности на диаграммем
    const setEntPosition = useCallback(
        async (ent, x, y) => {
            await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_ENT_POSITION_SET", args: { NRN: query, SID: ent, NX: x, NY: y }, loader: false });
        },
        [query, executeStored]
    );

    //Возвращаем интерфейс хука
    return { addEnt, removeEnt, setEntPosition };
};

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

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

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

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

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

    //Установка атрибутов сущности
    const setAttrs = useCallback(
        async attrs => {
            await executeStored({
                stored: "PKG_P8PANELS_QE.QUERY_ENT_ATTRS_SET",
                args: {
                    NRN: query,
                    SID: entity,
                    CATTRS: {
                        VALUE: object2Base64XML(attrs, { arrayNodeName: "XATTR", ignoreAttributes: false, attributeNamePrefix: "" }),
                        SDATA_TYPE: SERV_DATA_TYPE_CLOB
                    }
                },
                loader: false
            });
        },
        [query, entity, executeStored, SERV_DATA_TYPE_CLOB]
    );

    //При необходимости получить/обновить данные
    useEffect(() => {
        //Загрузка данных с сервера
        const loadData = async () => {
            try {
                setLoading(true);
                const data = await executeStored({
                    stored: "PKG_P8PANELS_QE.QUERY_ENT_ATTRS_GET",
                    args: { NRN: query, SID: entity },
                    respArg: "COUT",
                    isArray: name => ["XATTR"].includes(name),
                    attributeValueProcessor: (name, val) => (["name", "title", "agg"].includes(name) ? undefined : val),
                    loader: true
                });
                setData(data?.XATTRS?.XATTR || []);
            } finally {
                setRefresh(false);
                setLoading(false);
            }
        };
        //Если надо обновить
        if (refresh)
            //Получим данные
            loadData();
    }, [refresh, query, entity, executeStored]);

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

//Отложенное значение
const useDebounce = (value, delay) => {
    //Собственное состояние
    const [debouncedValue, setDebouncedValue] = useState(value);

    //При изменении интервала или значения
    useEffect(() => {
        //Взводим таймер
        const handler = setTimeout(() => {
            setDebouncedValue(value);
        }, delay);
        //Сбрасываем таймер при отмонтировании или изменении зависимостей
        return () => clearTimeout(handler);
    }, [value, delay]);

    //Возвращаем отложенное значение
    return debouncedValue;
};

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

export { useEntities, useQueryEntities, useEntityAttrs, useDebounce };
