/*
    Парус 8 - Панели мониторинга - Редактор настройки регламентированного отчёта
    Пользовательские хуки
*/

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

import { useState, useContext, useEffect, useCallback, useLayoutEffect } from "react"; //Классы React
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
import { NavigationCtx } from "../../context/navigation"; //Контекст навигации
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
import { STATUSES } from "./IUD/iud_form_dialog"; //Статусы диалогов
import { TEXTS } from "../../../app.text"; //Тексты для ошибок

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

//Хук для отработки изменений ширины и высоты рабочей области окна
const useWindowResize = () => {
    //Состояние размера рабочей области
    const [size, setSize] = useState([0, 0]);

    //При изменении размера
    useLayoutEffect(() => {
        const updateSize = () => {
            setSize([document.documentElement.clientWidth, document.documentElement.clientHeight]);
        };
        window.addEventListener("resize", updateSize);
        updateSize();
        return () => window.removeEventListener("resize", updateSize);
    }, []);

    //Вернём размеры
    return size;
};

//Хук для настройки регламентированного отчета
const useConf = (currentTab, handleSectionChange) => {
    //Собственное состояние - таблица данных
    const dataGrid = {
        rn: 0,
        code: "",
        name: "",
        dataLoaded: false,
        columnsDef: [],
        groups: [],
        rows: [],
        fixedHeader: false,
        fixedColumns: 0,
        reload: false
    };

    //Собственное состояние
    const [rrpConf, setRrpConf] = useState({
        docLoaded: false,
        sections: [],
        reload: true
    });

    //Состояние массива данных разделов
    const [dataGrids] = useState([]);

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

    //Подключение к контексту навигации
    const { getNavigationSearch } = useContext(NavigationCtx);

    //При необходимости обновить
    const handleReload = useCallback(async () => {
        setRrpConf(pv => ({ ...pv, reload: true }));
    }, []);

    //Загрузка данных разделов регламентированного отчёта
    const loadData = useCallback(async () => {
        if (rrpConf.reload) {
            //Переменная номера раздела с фокусом
            let tabFocus = currentTab ? currentTab : 0;
            const data = await executeStored({
                stored: "PKG_P8PANELS_RRPCONFED.RRPCONF_GET_SECTIONS",
                args: {
                    NRN_RRPCONF: Number(getNavigationSearch().NRN)
                },
                respArg: "COUT"
            });
            //Флаг первой загрузки данных
            let firstLoad = dataGrids.length == 0 ? true : false;
            //Копирование массива уже загруженных разделов
            let cloneDGs = dataGrids.slice();
            //Массив из нескольких разделов и из одного
            const sections = data.SECTIONS ? (data.SECTIONS.length ? data.SECTIONS : [data.SECTIONS]) : [];
            //Заполнение очередного раздела по шаблону
            sections.map(s => {
                let dg = {};
                Object.assign(dg, dataGrid, {
                    rn: s.NRN,
                    code: s.SCODE,
                    name: s.SNAME,
                    delete_allow: s.NDELETE_ALLOW,
                    dataLoaded: true,
                    columnsDef: [...(s.XDATA.XCOLUMNS_DEF || [])],
                    groups: [...(s.XDATA.XGROUPS || [])],
                    rows: [...(s.XDATA.XROWS || [])],
                    fixedHeader: s.XDATA.XDATA_GRID.fixedHeader,
                    fixedColumns: s.XDATA.XDATA_GRID.fixedColumns,
                    reload: false
                });
                //Если раздел имеет составы показателей
                if (s.MARK_CNS.MARK_CN) {
                    //Обходим строки раздела
                    dg.rows.map(row => {
                        //Цикл по ключам строки
                        for (let key in row) {
                            //Если это ключ для группы составов показателей
                            if (key.match(/MARK_CNS_.*/)) {
                                //Считываем рег. номер показателя
                                let markRn = key.substring(9);
                                //Переносим из раздела
                                row[key] = Array.isArray(s.MARK_CNS.MARK_CN)
                                    ? [...s.MARK_CNS.MARK_CN].filter(el => el.NPRN === row[`NMARK_RN_${markRn}`])
                                    : s.MARK_CNS.MARK_CN.NPRN === row[`NMARK_RN_${markRn}`]
                                    ? [s.MARK_CNS.MARK_CN]
                                    : null;
                            }
                        }
                    });
                }
                //Ищем загружен ли уже раздел с таким же ид.
                const dgItem = dataGrids.find(x => x.rn === dg.rn);
                //Его индекс, если нет соответствия, то -1
                let index = dataGrids.indexOf(dgItem);
                //Если было соответствие
                if (dgItem) {
                    //Если в нём не найдено изменений
                    if (JSON.stringify(dgItem, null, 4) === JSON.stringify(dg, null, 4)) {
                        //То из копированного массива его удаляем
                        cloneDGs.splice(cloneDGs.indexOf(cloneDGs.find(x => x.rn === dgItem.rn)), 1);
                    } else {
                        //Иначе обновляем раздел в массиве
                        dataGrids[index] = dg;
                        //Удаляем из копированного массива
                        cloneDGs.splice(cloneDGs.indexOf(cloneDGs.find(x => x.rn === dg.rn)), 1);
                        //Устанавливаем фокус на обновлённый раздел
                        tabFocus = index;
                    }
                } else {
                    //Если раздел новый, то добавляем его в массив данных
                    dataGrids.push(dg);
                    //И устанавливаем на него фокус, если флаг первой загрузки = false
                    tabFocus = !firstLoad ? dataGrids.length - 1 : 0;
                }
            });
            //Обходим разделы, что остались в копированном массиве (на удаление)
            cloneDGs.map(s => {
                let curIndex = dataGrids.indexOf(dataGrids.find(x => x.rn === s.rn));
                //Устаревший раздел удаляем из массива данных
                dataGrids.splice(curIndex, 1);
                //Фокус на предшествующий раздел
                if (curIndex > 0) tabFocus = curIndex - 1;
                //Иначе фокус на следующий, если был удалён первый раздел
                else tabFocus = curIndex;
            });
            setRrpConf(pv => ({
                ...pv,
                docLoaded: true,
                reload: false,
                sections: dataGrids
            }));
            handleSectionChange(tabFocus);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [rrpConf.reload, rrpConf.docLoaded, dataGrid.reload, dataGrid.docLoaded, executeStored]);

    //При необходимости обновить данные таблицы
    useEffect(() => {
        loadData();
    }, [rrpConf.reload, dataGrid.reload, loadData]);

    return [rrpConf, handleReload];
};

//Хук для вкладки
const useTab = () => {
    //Состояние раздела
    const [tabValue, setTabValue] = useState("");

    //Переключение раздела
    const handleSectionChange = useCallback(newValue => {
        setTabValue(newValue);
    }, []);

    return [tabValue, handleSectionChange];
};

//Хук для функций открытия записей
const useRecOpen = handleReload => {
    //Подключение к контексту взаимодействия с сервером
    const { executeStored } = useContext(BackEndСtx);

    //Подключение к контексту приложения
    const { pOnlineShowDictionary } = useContext(ApplicationСtx);

    //Подключение к контексту сообщений
    const { showMsgErr } = useContext(MessagingСtx);

    //Отображение показателя раздела
    const handleMarkOpen = useCallback(
        async nRrpConfSctnMrk => {
            const data = await executeStored({
                stored: "PKG_P8PANELS_RRPCONFED.RRPCONFSCTNMRK_GET_CODES",
                args: {
                    NRN: nRrpConfSctnMrk
                },
                tagValueProcessor: () => undefined
            });
            if (data) {
                pOnlineShowDictionary({
                    unitCode: "RRPConfig",
                    showMethod: "main_mrk_settings",
                    inputParameters: [
                        { name: "in_CODE", value: data.SRRPCONF },
                        { name: "in_SCTN_CODE", value: data.SRRPCONFSCTN },
                        { name: "in_MRK_CODE", value: data.SRRPCONFSCTNMRK }
                    ],
                    callBack: res => {
                        res.success ? handleReload() : null;
                    }
                });
            } else showMsgErr(TEXTS.NO_DATA_FOUND);
        },
        [executeStored, handleReload, pOnlineShowDictionary, showMsgErr]
    );

    //Отображение показателя раздела
    const handleMarkCnOpen = useCallback(
        async (nRrpConfSctnMrk, nRrpConfSctnMrkCn) => {
            pOnlineShowDictionary({
                unitCode: "RRPConfigSectionMark",
                showMethod: "link_cn",
                inputParameters: [
                    { name: "in_RN", value: nRrpConfSctnMrk },
                    { name: "in_RRPCONFSCTNMRKCN", value: nRrpConfSctnMrkCn }
                ],
                callBack: res => {
                    res.success ? handleReload() : null;
                }
            });
        },
        [handleReload, pOnlineShowDictionary]
    );

    //Отображение показателя раздела
    const handleMarkCnInsert = useCallback(
        async nRrpConfSctnMrk => {
            pOnlineShowDictionary({
                unitCode: "RRPConfigSectionMarkConstitution",
                showMethod: "link_add",
                inputParameters: [{ name: "in_PRN", value: nRrpConfSctnMrk }],
                callBack: res => {
                    res.success ? handleReload() : null;
                }
            });
        },
        [handleReload, pOnlineShowDictionary]
    );

    return [handleMarkOpen, handleMarkCnOpen, handleMarkCnInsert];
};

//Хук для форм диалогового окна
const useFormDialog = () => {
    //Состояние открытия диалогового окна
    const [formOpen, setForm] = useState(false);

    //Состояние диалогового окна
    const [formData, setFormData] = useState({
        reload: false,
        rn: "",
        prn: "",
        sctnName: "",
        sctnCode: "",
        status: "",
        code: "",
        name: "",
        colCode: "",
        colRn: null,
        rowCode: "",
        rowRn: null
    });

    //Подключение к контексту навигации
    const { getNavigationSearch } = useContext(NavigationCtx);

    //Открытие диалогового окна
    const openForm = () => {
        setForm(true);
    };

    //Очистка диалогового окна
    const clearFormData = () => {
        setFormData({
            reload: false,
            rn: "",
            prn: "",
            sctnName: "",
            sctnCode: "",
            status: "",
            code: "",
            name: "",
            colCode: "",
            colRn: null,
            rowCode: "",
            rowRn: null
        });
    };

    //Отработка нажатия на кнопку добавления секции
    const handleSectionAdd = () => {
        setFormData({ status: STATUSES.CREATE, prn: Number(getNavigationSearch().NRN) });
        openForm();
    };

    //Отработка нажатия на кнопку исправления секции
    const handleSectionEdit = (rn, code, name) => {
        setFormData({ rn: rn, code: code, name: name, status: STATUSES.EDIT });
        openForm();
    };

    //Отработка нажатия на кнопку удаления секции
    const handleSectionDelete = (rn, code, name) => {
        setFormData({ rn: rn, code: code, name: name, status: STATUSES.DELETE });
        openForm();
    };

    //Отработка нажатия на кнопку добавления показателя раздела
    const handleMarkAdd = (prn, rowRn = null, rowCode = "", colRn = null, colCode = "") => {
        setFormData({
            reload: rowRn && colRn ? true : false,
            prn: prn,
            rowRn: rowRn,
            rowCode: rowCode,
            colRn: colRn,
            colCode: colCode,
            status: STATUSES.RRPCONFSCTNMRK_CREATE
        });
        openForm();
    };

    //Отработка нажатия на кнопку исправления показателя раздела
    const handleMarkEdit = rn => {
        setFormData({ reload: true, rn: rn, status: STATUSES.RRPCONFSCTNMRK_EDIT });
        openForm();
    };

    //Отработка нажатия на кнопку удаления показателя раздела
    const handleMarkDelete = rn => {
        setFormData({ rn: rn, status: STATUSES.RRPCONFSCTNMRK_DELETE });
        openForm();
    };

    //При закрытии диалога
    const handleDialogClose = () => {
        setForm(false);
        clearFormData();
    };

    return [
        formOpen,
        formData,
        handleSectionAdd,
        handleSectionEdit,
        handleSectionDelete,
        handleMarkAdd,
        handleMarkEdit,
        handleMarkDelete,
        handleDialogClose
    ];
};

//Формирование разделов
const a11yProps = index => {
    return {
        id: `simple-tab-${index}`,
        "aria-controls": `simple-tabpanel-${index}`
    };
};

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

export { useWindowResize, useConf, useTab, useRecOpen, useFormDialog, a11yProps };
