/*
    Парус 8 - Панели мониторинга - УДП - Доски задач
    Панель мониторинга: Корневая панель доски задач
*/

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

import React, { useEffect, useState, useCallback } from "react"; //Классы React
import { DragDropContext, Droppable } from "react-beautiful-dnd"; //Работа с drag&drop
import { Stack, Box, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
import { StatusCard } from "./components/status_card.js";
import { TaskDialog } from "./task_dialog.js"; //Компонент формы события
import { Filter } from "./filter.js"; //Компонент фильтров
import { useExtraData, useColorRules, useStatuses } from "./hooks/hooks.js"; //Вспомогательные хуки
import { useTasks } from "./hooks/tasks_hooks.js"; //Хук событий
import { useFilters } from "./hooks/filter_hooks.js"; //Вспомогательные хуки фильтра
import { NoteDialog } from "./components/note_dialog.js"; //Диалог примечания
import { SettingsDialog } from "./components/settings_dialog.js"; //Диалог дополнительных настроек
import { deepCopyObject } from "../../core/utils.js"; //Вспомогательные функции
import { COMMON_STYLES } from "./styles"; //Общие стили
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы

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

//Высота фильтра
const FILTER_HEIGHT = "56px";

//Стили
const STYLES = {
    CONTAINER: { width: "100%", padding: 0 },
    BOX_FILTER: { display: "flex", alignItems: "center" },
    ICON_BUTTON_SETTINGS: { marginLeft: "auto" },
    STACK_STATUSES: { maxWidth: "99vw", paddingBottom: "5px", overflowX: "auto", ...COMMON_STYLES.SCROLL },
    BOX_STATUSES: { position: "fixed", left: "8px", top: `calc(${APP_BAR_HEIGHT} + ${FILTER_HEIGHT})` }
};

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

//Корневая панель доски задач
const ClntTaskBoard = () => {
    //Состояние фильтров
    const [filters, handleFiltersChange] = useFilters();

    //Состояние текущего загруженного фильтра
    const [filterTypeLoaded, setFilterTypeLoaded] = useState(filters.values.sType);

    //Состояние вспомогательных диалогов
    const [dialogsState, setDialogsState] = useState({
        filterDialogIsOpen: filters.isSetByUser,
        settingsDialogIsOpen: false,
        noteDialog: { isOpen: false, callback: null },
        taskDialogIsOpen: false
    });

    //Состояние сортировок
    const [orders, setOrders] = useState([]);

    //Состояние дополнительных данных
    const [extraData, setExtraData, handleDocLinksLoad] = useExtraData(filters.values.sType);

    //Состояние статусов событий
    const [statuses, statusesState, setStatuses, setStatusesState] = useStatuses(filters.values.sType);

    //Состояние пользовательских настроек заливки событий
    const [colorRules, setColorRules] = useColorRules();

    //Состояние событий
    const [tasks, setTasks, onDragEnd] = useTasks(filters.values, orders);

    //Состояние доступных маршрутов события
    const [availableRoutes, setAvailableRoutes] = useState({ source: "", routes: [] });

    //При открытии/закрытии диалога фильтра
    const handleFilterOpen = isOpen => {
        setDialogsState(pv => ({ ...pv, filterDialogIsOpen: isOpen }));
    };

    //При открытии/закрытии диалога дополнительных настроек
    const handleSettingsOpen = () => setDialogsState(pv => ({ ...pv, settingsDialogIsOpen: !pv.settingsDialogIsOpen }));

    //При открытии/закрытии диалога примечания
    const handleNoteOpen = (cb = null) => {
        setDialogsState(pv => ({ ...pv, noteDialog: { isOpen: !dialogsState.noteDialog.isOpen, callback: cb ? v => cb(v) : null } }));
    };

    //При открытии/закрытии диалога события
    const handleTaskDialogOpen = () => setDialogsState(pv => ({ ...pv, taskDialogIsOpen: !dialogsState.taskDialogIsOpen }));

    //При необходимости обновить дополнительные данные
    const handleExtraDataReload = useCallback(() => {
        setExtraData(pv => ({ ...pv, reload: true }));
    }, [setExtraData]);

    //При необходимости обновить информацию о событиях
    const handleTasksReload = useCallback(
        (bAccountsReload = true) => {
            setTasks(pv => ({ ...pv, reload: true, accountsReload: bAccountsReload }));
        },
        [setTasks]
    );

    //При необходимости обновить состояние статусов
    const handleStatusesStateReload = useCallback(() => {
        setStatusesState(pv => ({ ...pv, reload: true, sorted: false }));
    }, [setStatusesState]);

    //При изменении дополнительных настроек
    const handleSettingsChange = (newSettings, statusesState) => {
        setColorRules(pv => ({ ...pv, selectedColorRule: newSettings.selectedColorRule }));
        setStatusesState({ ...statusesState, sorted: false });
    };

    //При изменении цвета карточки статуса
    const handleSettingStatusColorChange = (changedStatus, newColor) => {
        //Считываем массив статусов
        let newStatuses = [...statuses];
        //Изменяем цвет нужного статуса
        newStatuses.find(status => status.ID === changedStatus.ID).color = newColor;
        //Обновляем состояние
        setStatuses([...newStatuses]);
    };

    //При изменении сортировки
    const handleOrderChanged = columnName => {
        //Копируем состояние сортировки
        let newOrders = deepCopyObject(orders);
        //Находим сортируемую колонку
        const orderedColumn = newOrders.find(o => o.name == columnName);
        //Определяем направление сортировки
        const newDirection = orderedColumn?.direction == "ASC" ? "DESC" : orderedColumn?.direction == "DESC" ? null : "ASC";
        //Если сортировка отключается - очищаем информацию о сортировке
        if (newDirection == null && orderedColumn) newOrders.splice(newOrders.indexOf(orderedColumn), 1);
        //Если сортировки не было - устанавливаем
        if (newDirection != null && !orderedColumn) newOrders.push({ name: columnName, direction: newDirection });
        //Если сортировка была и не отключается - изменяем
        if (newDirection != null && orderedColumn) orderedColumn.direction = newDirection;
        //Устанавливаем новую сортировку
        setOrders(newOrders);
    };

    //При необходимости очистки доступных маршрутов события
    const handleAvailableRoutesStateClear = () => {
        setAvailableRoutes({ source: "", routes: [] });
    };

    //Проверка доступности карточки события
    const isCardAvailable = code => {
        return availableRoutes.source === code || availableRoutes.routes.find(r => r.SDESTINATION === code) || !availableRoutes.source ? true : false;
    };

    //При изменении фильтра
    useEffect(() => {
        //Если изменился тип
        if (filters.loaded && filters.values.sType) {
            //Если тип события изменился
            if (filterTypeLoaded !== filters.values.sType) {
                //Обновляем информацию о дополнительных данных
                handleExtraDataReload();
                //Обновляем информацию о статусах
                handleStatusesStateReload();
                //Обновляем текущий загруженный тип события
                setFilterTypeLoaded(filters.values.sType);
            }
            //Обновляем информацию о событиях
            handleTasksReload();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [filters.loaded, filters.values]);

    //При изменении сортировки
    useEffect(() => {
        //Если есть все данные для загрузки событий
        if (filters.loaded && filters.values.sType) {
            //Обновляем информацию о событиях без обновления контрагентов
            handleTasksReload(false);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [orders]);

    //Генерация содержимого
    return (
        <Box sx={STYLES.CONTAINER}>
            {dialogsState.settingsDialogIsOpen ? (
                <SettingsDialog
                    initial={{ colorRules: colorRules, statusesState: statusesState }}
                    onSettingsChange={handleSettingsChange}
                    onClose={handleSettingsOpen}
                />
            ) : null}
            {dialogsState.taskDialogIsOpen ? (
                <TaskDialog taskType={filters.values.sType} onTasksReload={() => handleTasksReload(true)} onClose={handleTaskDialogOpen} />
            ) : null}
            <Box sx={STYLES.BOX_FILTER}>
                <Stack direction="row">
                    <Box>
                        <Stack direction="row" pl={1} pt={1}>
                            <IconButton onClick={handleTaskDialogOpen} title={"Добавить событие"}>
                                <Icon>add</Icon>
                            </IconButton>
                        </Stack>
                    </Box>
                    <Filter
                        isFilterDialogOpen={dialogsState.filterDialogIsOpen}
                        filter={filters.values}
                        docLinks={extraData.docLinks}
                        selectedDocLink={filters.values.sDocLink ? extraData.docLinks.find(d => d.NRN === filters.values.sDocLink) : null}
                        onFilterChange={handleFiltersChange}
                        onDocLinksLoad={handleDocLinksLoad}
                        onFilterOpen={() => handleFilterOpen(true)}
                        onFilterClose={() => handleFilterOpen(false)}
                        onTasksReload={handleTasksReload}
                        orders={orders}
                        onOrderChanged={handleOrderChanged}
                    />
                </Stack>
                <IconButton title="Настройки" onClick={handleSettingsOpen} sx={STYLES.ICON_BUTTON_SETTINGS}>
                    <Icon>settings</Icon>
                </IconButton>
            </Box>
            {dialogsState.noteDialog.isOpen ? (
                <NoteDialog noteTypes={extraData.noteTypes} onCallback={note => dialogsState.noteDialog.callback(note)} onClose={handleNoteOpen} />
            ) : null}
            {filters.loaded && filters.values.sType && extraData.dataLoaded && tasks.loaded ? (
                <DragDropContext
                    onDragStart={path => {
                        //Поиск кода текущего статуса задачи
                        let sourceCode = statuses.find(status => status.ID == path.source.droppableId).SEVNSTAT_CODE;
                        //Устанавливаем доступные маршруты события
                        setAvailableRoutes({ source: sourceCode, routes: [...extraData.evRoutes.filter(route => route.SSOURCE === sourceCode)] });
                    }}
                    onDragEnd={path => {
                        //Если есть статус назначения
                        if (path.destination) {
                            //Определяем мнемокод статуса назначения
                            let destCode = statuses.find(status => status.ID == path.destination.droppableId).SEVNSTAT_CODE;
                            //Переносим событие
                            onDragEnd({ path: path, eventPoints: extraData.evPoints, openNoteDialog: handleNoteOpen, destCode: destCode });
                        }
                        //Очищаем информацию о доступных маршрутах события
                        handleAvailableRoutesStateClear();
                    }}
                >
                    <Box sx={STYLES.BOX_STATUSES}>
                        <Droppable droppableId="Statuses" type="droppableTask">
                            {provided => (
                                <div ref={provided.innerRef}>
                                    <Stack direction="row" spacing={2} sx={STYLES.STACK_STATUSES}>
                                        {statusesState.sorted
                                            ? statuses.map((status, index) => (
                                                  <div key={index}>
                                                      <Droppable
                                                          isDropDisabled={!isCardAvailable(status.SEVNSTAT_CODE)}
                                                          droppableId={status.ID.toString()}
                                                      >
                                                          {provided => (
                                                              <div ref={provided.innerRef}>
                                                                  <StatusCard
                                                                      tasks={tasks}
                                                                      status={status}
                                                                      statusTitle={status[statusesState.attr] || status.SEVNSTAT_NAME}
                                                                      colorRules={colorRules}
                                                                      extraData={extraData}
                                                                      isCardAvailable={isCardAvailable}
                                                                      onTasksReload={handleTasksReload}
                                                                      onNoteDialogOpen={handleNoteOpen}
                                                                      onStatusColorChange={handleSettingStatusColorChange}
                                                                      placeholder={provided.placeholder}
                                                                  />
                                                              </div>
                                                          )}
                                                      </Droppable>
                                                  </div>
                                              ))
                                            : null}
                                    </Stack>
                                    {provided.placeholder}
                                </div>
                            )}
                        </Droppable>
                    </Box>
                </DragDropContext>
            ) : null}
        </Box>
    );
};

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

export { ClntTaskBoard };
