/*
    Парус 8 - Панели мониторинга
    Хуки для индикаторов
*/

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

import { useState, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React
import { BackEndCtx } from "../context/backend"; //Контекст взаимодействия с сервером
import { P8P_INDICATOR_STATE, P8P_INDICATOR_VARIANT } from "./p8p_indicator";

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

//Константы - значения по умолчанию
const RESP_ARG_DEF = "COUT"; //Имя параметра, содержащего информацию об индикаторе
const INDICATOR_NODE_NAME_DEF = "XINDICATOR"; //Наименование узла, содержащего информацию об индикаторе
const ELEVATION_DEF = 3; //Высота парения

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

//Хук для P8PIndicator
const useP8PIndicator = ({
    stored,
    respArg = RESP_ARG_DEF,
    contentNodeName = INDICATOR_NODE_NAME_DEF,
    storedArgs = {},
    executeStoredArgs = {},
    allowDataLoad = () => true
}) => {
    //Собственное состояние - индикатор
    const [indicator, setIndicator] = useState({
        caption: null,
        value: null,
        icon: null,
        state: P8P_INDICATOR_STATE.UNDEFINED,
        square: false,
        elevation: ELEVATION_DEF,
        variant: P8P_INDICATOR_VARIANT.ELEVATION,
        hint: null,
        backgroundColor: null,
        color: null
    });

    //Собственное состояние - признак загрузки данных
    const [isDataLoaded, setIsDataLoaded] = useState(false);

    //Собственное состояние - признак наличия бизнес-данных в загруженных
    const [isDataFound, setIsDataFound] = useState(false);

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

    //Собственное состояние - необходимость обновления данных
    const [reload, setReload] = useState(true);

    //Собственное состояние - дополнительные агрументы
    const refStoredArgs = useRef(storedArgs);

    //Собственное состояние - дополнительные параметры вызова процедуры
    const refExecuteStoredArgs = useRef(executeStoredArgs);

    //Признак допустимости обновления данных
    const isAllowDataLoad = useMemo(() => {
        return allowDataLoad();
    }, [allowDataLoad]);

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

    //Загрузка данных индикатора с сервера
    const loadData = useCallback(async () => {
        try {
            //Поднимаем флаг начала загрузки данных
            setLoading(true);
            //Получаем данные с сервера БД
            const data = await executeStored({ stored, respArg, args: { ...refStoredArgs.current }, ...refExecuteStoredArgs.current });
            //Устанавливаем флаг наличия бизнес-данных
            setIsDataFound(data[contentNodeName]?.caption && data[contentNodeName]?.value != undefined);
            //Устанавливаем бизнес-данные
            setIndicator(pv => ({ ...pv, ...data[contentNodeName] }));
            //Устанавливаем признак загрузки данных с учетом возможных ошибок
            setIsDataLoaded(!isRespErr(data));
        } catch (e) {
            //Если произошла ошибка - данные не загружены
            setIsDataLoaded(false);
        } finally {
            //Сбрасываем признаки загрузки и перезагрузки данных
            setLoading(false);
            setReload(false);
        }
    }, [contentNodeName, executeStored, isRespErr, respArg, stored]);

    //При необходимости обновления индикатора
    const doReload = useCallback(() => {
        setReload(true);
    }, []);

    //Проверка изменений параметров
    const isArgsChanged = useCallback(
        (currentArgs, args) => {
            //Если дополнительные параметры изменились (и сейчас не происходит загрузка данных с сервера)
            return !isLoading && JSON.stringify(currentArgs) != JSON.stringify(args);
        },
        [isLoading]
    );

    //При изменение дополнительных параметров процедуры
    useEffect(() => {
        //Если параметры изменились
        if (isArgsChanged(refStoredArgs.current, storedArgs)) {
            //Устанавливаем новые дополнительные параметры
            refStoredArgs.current = storedArgs;
            //При изменении дополнительных параметров необходимо перезагрузить данные
            setReload(true);
        }
    }, [storedArgs, isArgsChanged]);

    //При изменение дополнительных параметров вызова процедуры
    useEffect(() => {
        //Если параметры изменились
        if (isArgsChanged(refExecuteStoredArgs.current, executeStoredArgs)) {
            //Устанавливаем новые дополнительные параметры
            refExecuteStoredArgs.current = executeStoredArgs;
            //При изменении дополнительных параметров необходимо перезагрузить данные
            setReload(true);
        }
    }, [executeStoredArgs, isArgsChanged]);

    //При необходимости обновить данные индикатора
    useEffect(() => {
        //Если необходимо перезагрузить данные и это допустимо
        if (isAllowDataLoad && reload) {
            loadData();
        }
    }, [isAllowDataLoad, reload, loadData]);

    //Возвращаем данные индикатора
    return { indicator, isDataLoaded, isDataFound, isLoading, doReload };
};

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

export { useP8PIndicator };
