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

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

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

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

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

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

//Хук для P8PCyclogram
const useP8PCyclogram = ({
    stored,
    respArg = RESP_ARG_DEF,
    contentNodeName = CG_NODE_NAME_DEF,
    storedArgs = {},
    executeStoredArgs = {},
    allowDataLoad = () => true
}) => {
    //Собственное состояние - циклограмма
    const [cyclogram, setCyclogram] = useState({
        columns: [],
        groups: [],
        tasks: [],
        taskAttributes: [],
        title: null,
        lineHeight: 0,
        zoom: 1,
        zoomBar: true
    });

    //Собственное состояние - признак загрузки данных
    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,
                args: { ...refStoredArgs.current },
                attributeValueProcessor: (name, val) => (["ddate_start", "ddate_end"].includes(name) ? formatDateJSONDateOnly(val) : val),
                respArg,
                ...refExecuteStoredArgs.current
            });
            //Устанавливаем флаг наличия бизнес-данных
            setIsDataFound(data[contentNodeName]?.tasks?.length > 0);
            //Устанавливаем бизнес-данные
            setCyclogram(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 { cyclogram, isDataLoaded, isDataFound, isLoading, doReload };
};

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

export { useP8PCyclogram };
