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

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

import React, { useState, useContext, useCallback, useEffect } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Draggable } from "react-beautiful-dnd"; //Работа с drag&drop
import { Card, CardHeader, Typography, IconButton, Icon, Box, Menu, MenuItem, CardContent, Avatar, Stack } from "@mui/material"; //Интерфейсные компоненты
import { TaskDialog } from "../task_dialog"; //Форма события
import { ApplicationCtx } from "../../../context/application"; //Контекст приложения
import { BackEndCtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
import { MessagingCtx } from "../../../context/messaging"; //Контекст сообщений
import { TASK_COLORS, getTaskExpiredColor, getTaskBgColorByRule, makeCardActionsArray } from "../layouts"; //Дополнительная разметка и вёрстка клиентских элементов
import { useDictionary } from "../hooks/dict_hooks"; //Состояние открытия разделов
import { useTasksFunctions } from "../hooks/tasks_hooks"; //Состояние вспомогательных функций событий

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

//Стили
const STYLES = {
    MENU_ITEM_DELIMITER: { borderBottom: "1px solid lightgrey" },
    CARD: (task, colorRule) => {
        const expiredColor = getTaskExpiredColor(task);
        const backgroundColor = task.nClosed ? "#d3d3d3" : colorRule.SCOLOR ? getTaskBgColorByRule(task, colorRule) : null;
        return {
            ...(expiredColor ? { borderLeft: `solid ${expiredColor}` } : {}),
            ...(backgroundColor ? { backgroundColor: backgroundColor } : {})
        };
    },
    CARD_HEADER_TITLE: {
        padding: "4px",
        width: "292px",
        display: "-webkit-box",
        hyphens: "auto",
        WebkitBoxOrient: "vertical",
        WebkitLineClamp: 2,
        overflow: "hidden"
    },
    CARD_HEADER: { padding: 0, cursor: "pointer" },
    CARD_CONTENT: { padding: "4px !important" },
    CARD_CONTENT_BOX: { display: "flex", alignItems: "center", width: "100%" },
    STACK_SENDER: { alignItems: "center", marginLeft: "auto", width: "50%", justifyContent: "flex-end", paddingLeft: "10px", gap: "5px" },
    TYPOGRAPHY_TASK: { color: "text.secondary", fontSize: 14, width: "40%", overflow: "hidden" },
    TYPOGRAPHY_SENDER: { color: "text.secondary", fontSize: 14, width: "80%", overflow: "hidden", textAlign: "end" },
    ICON_COLOR: linked => {
        return { color: theme => (linked ? TASK_COLORS.LINKED : theme.palette.grey[500]), width: "10%" };
    }
};

//------------------------------------
//Вспомогательные функции и компоненты
//------------------------------------

//Действия карточки события
const CardActions = ({
    taskRn,
    taskClosed,
    menuItems,
    cardActions,
    onMethodsMenuButtonClick,
    onMethodsMenuClose,
    onTasksReload,
    pointSettings,
    onOpenNoteDialog
}) => {
    //При нажатии на действие меню
    const handleActionClick = action => {
        //Выполняем действие
        action.func({
            nEvent: taskRn,
            onReload: action.tasksReload ? () => onTasksReload(action.needAccountsReload) : null,
            onNoteOpen: pointSettings.ADDNOTE_ONSEND ? onOpenNoteDialog : null
        });
        //Закрываем меню действий
        onMethodsMenuClose();
    };

    return (
        <Box sx={STYLES.BOX_ROW}>
            <IconButton id={`${taskRn}_menu_button`} aria-haspopup="true" onClick={onMethodsMenuButtonClick}>
                <Icon>more_vert</Icon>
            </IconButton>
            <Menu id={`${taskRn}_menu`} anchorEl={cardActions.anchorMenuMethods} open={cardActions.openMethods} onClose={onMethodsMenuClose}>
                {menuItems.map(action =>
                    action.visible ? (
                        <MenuItem
                            sx={action.delimiter ? STYLES.MENU_ITEM_DELIMITER : {}}
                            key={`${taskRn}_${action.method}`}
                            onClick={() => handleActionClick(action)}
                            disabled={taskClosed === 1 && action.disableClosed ? true : false}
                        >
                            <Icon>{action.icon}</Icon>
                            <Typography pl={1}>{action.name}</Typography>
                        </MenuItem>
                    ) : null
                )}
            </Menu>
        </Box>
    );
};

//Контроль свойств - Действия карточки события
CardActions.propTypes = {
    taskRn: PropTypes.number.isRequired,
    taskClosed: PropTypes.oneOf([0, 1]).isRequired,
    menuItems: PropTypes.array.isRequired,
    cardActions: PropTypes.object.isRequired,
    onMethodsMenuButtonClick: PropTypes.func.isRequired,
    onMethodsMenuClose: PropTypes.func.isRequired,
    onTasksReload: PropTypes.func,
    pointSettings: PropTypes.object,
    onOpenNoteDialog: PropTypes.func
};

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

//Карточка события
const TaskCard = ({ task, index, onTasksReload, colorRule, pointSettings, onOpenNoteDialog }) => {
    //Состояние диалога события
    const [taskDialogOpen, setTaskDialogOpen] = useState(false);

    //Состояние действий события
    const [cardActions, setCardActions] = useState({ anchorMenuMethods: null, openMethods: false });

    //Состояние списка действий меню
    const [menuItems, setMenuItems] = useState([]);

    //Вспомогательные функции открытия раздела
    const { handleClientEventsOpen, handleClientEventsNotesOpen, handleFileLinksOpen, handleCatalogTreeOpen } = useDictionary();

    //Состояние вспомогательных функций событий
    const { handleTaskStateChange, handleTaskSend } = useTasksFunctions();

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

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

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

    //По нажатию на открытие меню действий
    const handleMethodsMenuButtonClick = useCallback(event => {
        setCardActions(pv => ({ ...pv, anchorMenuMethods: event.currentTarget, openMethods: true }));
    }, []);

    //При закрытии меню
    const handleMethodsMenuClose = useCallback(() => {
        setCardActions(pv => ({ ...pv, anchorMenuMethods: null, openMethods: false }));
    }, []);

    //При удалении контрагента
    const handleTaskDelete = useCallback(
        async ({ nEvent, onReload }) => {
            await executeStored({
                stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_DELETE",
                args: { NCLNEVENTS: nEvent }
            });
            //Если требуется перезагрузить данные
            onReload ? onReload() : null;
        },
        [executeStored]
    );

    //При возврате в предыдущую точку события
    const handleTaskReturn = useCallback(
        async ({ nEvent, onReload }) => {
            await executeStored({
                stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_RETURN",
                args: { NCLNEVENTS: nEvent }
            });
            //Если требуется перезагрузить данные
            onReload ? onReload() : null;
        },
        [executeStored]
    );

    //При перемещении в каталог
    const handleTaskMove = useCallback(
        async ({ nEvent, nCrn, onReload }) => {
            await executeStored({
                stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_MOVE",
                args: { NCLNEVENTS: nEvent, NCRN: nCrn }
            });
            //Если требуется перезагрузить данные
            onReload ? onReload() : null;
        },
        [executeStored]
    );

    //По нажатию действия "Направить"
    const handleTaskSendAction = useCallback(
        async ({ nEvent, onReload, onNoteOpen }) => {
            //Выполняем направление события
            handleTaskSend({ nEvent, onReload, onNoteOpen });
        },
        [handleTaskSend]
    );

    //По нажатия действия "Редактировать"
    const handleTaskEditAction = useCallback(() => {
        setTaskDialogOpen(true);
    }, []);

    //По нажатия действия "Редактировать в разделе"
    const handleTaskEditClientAction = useCallback(
        async ({ nEvent }) => {
            const data = await executeStored({
                stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_SELECT",
                args: {
                    NCLNEVENTS: nEvent
                }
            });
            if (data.NIDENT) {
                //Открываем раздел "События" с фильтром по записи
                handleClientEventsOpen({ nIdent: data.NIDENT });
            }
        },
        [executeStored, handleClientEventsOpen]
    );

    //По нажатию действия "Удалить"
    const handleTaskDeleteAction = useCallback(
        ({ nEvent, onReload }) => {
            showMsgWarn("Удалить событие?", () => handleTaskDelete({ nEvent, onReload }));
        },
        [handleTaskDelete, showMsgWarn]
    );

    //По нажатию действия "Выполнить возврат"
    const handleTaskReturnAction = useCallback(
        ({ nEvent, onReload }) => {
            showMsgWarn("Выполнить возврат события в предыдущую точку?", () => handleTaskReturn({ nEvent, onReload }));
        },
        [handleTaskReturn, showMsgWarn]
    );

    //По нажатию действия "Примечания"
    const handleEventNotesOpenAction = useCallback(
        ({ nEvent }) => {
            handleClientEventsNotesOpen({ nPrn: nEvent });
        },
        [handleClientEventsNotesOpen]
    );

    //По нажатию действия "Присоединенные документы"
    const handleTaskFileLinksOpenAction = useCallback(
        ({ nEvent }) => {
            handleFileLinksOpen({ nPrn: nEvent, sUnitCode: "ClientEvents" });
        },
        [handleFileLinksOpen]
    );

    //По нажатию действия "Перейти"
    const handleTaskStateChangeAction = useCallback(
        async ({ nEvent, onReload, onNoteOpen }) => {
            //Выполняем изменения статуса события
            handleTaskStateChange({ nEvent, onReload, onNoteOpen });
        },
        [handleTaskStateChange]
    );

    //По нажатию действия "Переместить"
    const handleTaskMoveAction = useCallback(
        async ({ nEvent, onReload }) => {
            //Открываем выбор записи из раздела "Каталоги иерархии"
            handleCatalogTreeOpen({
                sUnitName: "ClientEvents",
                nRn: task.nCrn,
                callBack: res => {
                    //Выполняем перемещение события
                    handleTaskMove({
                        nEvent,
                        nCrn: res.outParameters.out_RN,
                        onReload
                    });
                }
            });
        },
        [handleCatalogTreeOpen, handleTaskMove, task.nCrn]
    );

    //При изменении ссылок в меню действий (для того, чтобы ссылка на объект менялась при реальной необходимости)
    useEffect(() => {
        //Устанавливаем список меню
        setMenuItems(
            makeCardActionsArray(
                handleTaskEditAction,
                handleTaskEditClientAction,
                handleTaskDeleteAction,
                handleTaskStateChangeAction,
                handleTaskReturnAction,
                handleTaskSendAction,
                handleEventNotesOpenAction,
                handleTaskFileLinksOpenAction,
                handleTaskMoveAction
            )
        );
    }, [
        handleEventNotesOpenAction,
        handleTaskFileLinksOpenAction,
        handleTaskSendAction,
        handleTaskStateChangeAction,
        handleTaskDeleteAction,
        handleTaskEditAction,
        handleTaskEditClientAction,
        handleTaskReturnAction,
        handleTaskMoveAction
    ]);

    //Генерация содержимого
    return (
        <Box>
            {taskDialogOpen ? (
                <TaskDialog
                    taskRn={task.nRn}
                    taskType={task.sType}
                    editable={pointSettings.BAN_UPDATE ? false : true}
                    onTasksReload={onTasksReload}
                    onClose={() => {
                        setTaskDialogOpen(false);
                    }}
                />
            ) : null}
            <Draggable draggableId={task.id.toString()} key={task.id} index={index}>
                {provided => (
                    <Card ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} sx={STYLES.CARD(task, colorRule)}>
                        <CardHeader
                            title={
                                <Typography
                                    className="task-info"
                                    sx={STYLES.CARD_HEADER_TITLE}
                                    lang="ru"
                                    onClick={() => {
                                        menuItems.find(action =>
                                            action.method === "EDIT" ? action.func(task.nRn, action.tasksReload ? onTasksReload : null) : null
                                        );
                                    }}
                                    title={task.sDescription}
                                >
                                    {task.sDescription}
                                </Typography>
                            }
                            sx={STYLES.CARD_HEADER}
                            action={
                                <CardActions
                                    taskRn={task.nRn}
                                    taskClosed={task.nClosed}
                                    menuItems={menuItems}
                                    cardActions={cardActions}
                                    onMethodsMenuButtonClick={handleMethodsMenuButtonClick}
                                    onMethodsMenuClose={handleMethodsMenuClose}
                                    onTasksReload={onTasksReload}
                                    pointSettings={pointSettings}
                                    onOpenNoteDialog={onOpenNoteDialog}
                                />
                            }
                        />
                        <CardContent sx={STYLES.CARD_CONTENT}>
                            <Box sx={STYLES.CARD_CONTENT_BOX}>
                                <IconButton
                                    title={task.nLinkedRn ? "Событие получено по статусной модели" : null}
                                    onClick={
                                        task.nLinkedRn ? () => pOnlineShowDocument({ unitCode: task.sLinkedUnit, document: task.nLinkedRn }) : null
                                    }
                                    sx={STYLES.ICON_COLOR(task.nLinkedRn)}
                                    disabled={!task.nLinkedRn}
                                >
                                    <Icon>assignment</Icon>
                                </IconButton>
                                <Typography sx={STYLES.TYPOGRAPHY_TASK} noWrap title={task.name}>
                                    {task.name}
                                </Typography>
                                {task.sSender ? (
                                    <Stack direction="row" spacing={0.5} sx={STYLES.STACK_SENDER}>
                                        <Typography sx={STYLES.TYPOGRAPHY_SENDER} title={task.sSender} noWrap>
                                            {task.sSender}
                                        </Typography>
                                        <Avatar src={task.avatar ? `data:image/png;base64,${task.avatar}` : null} />
                                    </Stack>
                                ) : null}
                            </Box>
                        </CardContent>
                    </Card>
                )}
            </Draggable>
        </Box>
    );
};

//Контроль свойств - Карточка события
TaskCard.propTypes = {
    task: PropTypes.object.isRequired,
    index: PropTypes.number.isRequired,
    onTasksReload: PropTypes.func,
    colorRule: PropTypes.object,
    pointSettings: PropTypes.object,
    onOpenNoteDialog: PropTypes.func
};

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

export { TaskCard };
