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

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

import React, { useState } from "react"; //Классы React
import { Grid, Box, Typography, Checkbox, Icon, Stack, Button, Tooltip, TextField } from "@mui/material"; //Интерфейсные элементы
import { APP_BAR_HEIGHT } from "../../components/p8p_app_workspace"; //Заголовок страницы
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
import { P8PDataGrid, P8P_DATA_GRID_SIZE, P8P_DATA_GRID_MORE_HEIGHT } from "../../components/p8p_data_grid"; //Таблица данных
import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения
import { useCostJobs, useCostJobsSpecs, useCostJobsWorkers } from "./hooks"; //Вспомогательные хуки
import { CostJobsSpecsInclude } from "./worker_include_dialog"; //Компонент диалога включения в задание
import { hasValue } from "../../core/utils"; //Вспомогательные функции

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

//Мнемокод раздела операций
const UNIT_COST_JOBS_SPECS = "CostJobsSpecs";

//Мнемокод раздела исполнений должности
const UNIT_WORKERS = "ClientPostPerform";

//Высота основного заголовка
const MAIN_HEADER_HEIGHT = "35px";

//Высота подзаголовка
const SUB_HEADER_HEIGHT = "35px";

//Высота заголовка таблицы
const TABLE_HEADER_HEIGHT = "35px";

//Высота панели кнопок таблицы
const TABLE_BUTTONS_HEIGHT = "35px";

//Отступ таблицы
const TABLE_PADDING_TOP = "15px";

//Формат для коэффициент выполнения норм
const issueCoeffFormat = /^(?!.*\..*\.)[0-9]{0,3}(\.[0-9]{0,1})?$/;

//Стили
const STYLES = {
    MAIN_HEADER: { height: MAIN_HEADER_HEIGHT, overflow: "hidden" },
    SUB_HEADER: { height: SUB_HEADER_HEIGHT, overflow: "hidden" },
    CONTAINER: { textAlign: "center" },
    TABLE: { paddingTop: TABLE_PADDING_TOP },
    TABLE_HEADER: { height: TABLE_HEADER_HEIGHT, overflow: "hidden" },
    TABLE_BUTTONS: { display: "flex", justifyContent: "flex-end", height: TABLE_BUTTONS_HEIGHT, overflow: "hidden", alignItems: "flex-end" },
    DATA_GRID_CONTAINER: morePages => ({
        height: `calc(100vh - ${APP_BAR_HEIGHT} - ${MAIN_HEADER_HEIGHT} - ${SUB_HEADER_HEIGHT} - ${TABLE_HEADER_HEIGHT} - ${TABLE_BUTTONS_HEIGHT} - ${TABLE_PADDING_TOP} - 32px - ${
            morePages ? P8P_DATA_GRID_MORE_HEIGHT : "0px"
        })`,
        ...APP_STYLES.SCROLL
    })
};

//Цвета
const colors = {
    LINKED: "#bce0de",
    UNAVAILABLE: "#949494",
    WITH_WORKER: "#82df83"
};

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

//Проверка правильности значения коэффициент выполнения норм
const isValidIssueCoeff = value => {
    return issueCoeffFormat.test(value);
};

//Форматирование значения ячейки
const dataCellRender = ({ row, columnDef, handleSelectChange, sUnit, selectedWorkerRows = [], selectedJobSpec }) => {
    //Стиль
    let cellStyle = {};
    //Если это рабочие
    if (sUnit === UNIT_WORKERS) {
        //Признак недоступности
        let disabled = true;
        //Если в выбранной строке смены указан исполнитель факт
        if (selectedJobSpec.NPERFORM_FACT) {
            //Если это текущей исполнитель
            if (selectedJobSpec.SWORKERS_LIST.includes(row["NRN"])) {
                //Подсвечиваем строку рабочего
                cellStyle = { backgroundColor: colors.LINKED };
            }
        } else {
            //Если выбрана строка смены
            if (selectedJobSpec.NRN) {
                //Если текущий рабочий может принять задание
                if (row["NLOADING"] < 100) {
                    //Подсвечиваем строку рабочего
                    cellStyle = { backgroundColor: colors.LINKED };
                    disabled = false;
                }
            }
        }
        //Если уже выбрано достаточное количество рабочих и текущий рабочий не отмечен
        if (selectedJobSpec.NRESOURCE_NUMB === selectedWorkerRows.length && !selectedWorkerRows.includes(row["NRN"])) {
            //Устанавливаем признак недоступности
            disabled = true;
        }
        //Если загрузка рабочего больше 100
        if (row["NLOADING"] >= 100) {
            //Если поле не поле выбора
            if (columnDef.name !== "NSELECT") {
                //Указываем, что рабочее место недоступно
                cellStyle = { ...cellStyle, color: colors.UNAVAILABLE };
            }
        }
        //Для колонки выбора
        if (columnDef.name === "NSELECT") {
            return {
                cellStyle,
                data: (
                    <Box sx={STYLES.CONTAINER}>
                        <Checkbox
                            disabled={disabled}
                            checked={selectedWorkerRows.includes(row["NRN"])}
                            onChange={() => handleSelectChange({ NRN: row["NRN"], SUNIT: sUnit, BFULL_LOADED: row["NLOADING"] >= 100 })}
                        />
                    </Box>
                )
            };
        }
        //Отформатированная колонка
        return {
            cellStyle,
            data: row[columnDef.name]
        };
    }
    //Если это сменное задание
    if (sUnit === UNIT_COST_JOBS_SPECS) {
        //Если указан исполнитель факт
        if (row["NPERFORM_FACT"]) {
            //Подсвечиваем сменное задание зеленым
            cellStyle = { ...cellStyle, backgroundColor: colors.WITH_WORKER };
        }
        //Для колонки выбора
        if (columnDef.name === "NSELECT") {
            return {
                cellStyle,
                data: (
                    <Box sx={STYLES.CONTAINER}>
                        <Checkbox
                            disabled={row["DBEG_FACT"] ? true : false}
                            checked={row["NRN"] === selectedJobSpec.NRN}
                            onChange={() =>
                                handleSelectChange({
                                    NRN: row["NRN"],
                                    SUNIT: sUnit,
                                    NPERFORM_FACT: row["NPERFORM_FACT"],
                                    NRESOURCE_NUMB: row["NRESOURCE_NUMB"],
                                    NQUANT_PLAN: row["NQUANT_PLAN"],
                                    SWORKERS_LIST: row["SWORKERS_LIST"]
                                })
                            }
                        />
                    </Box>
                )
            };
        }
        //Отформатированная колонка
        return {
            cellStyle,
            data: row[columnDef.name]
        };
    }
    //Необрабатываемый раздел
    return {
        data: row[columnDef.name]
    };
};

//Генерация представления ячейки заголовка группы
export const headCellRender = ({ columnDef }) => {
    if (columnDef.name === "NSELECT") {
        return {
            stackStyle: { padding: "2px", justifyContent: "space-around" },
            data: <Icon>done</Icon>
        };
    } else {
        return {
            stackStyle: { padding: "2px" },
            data: columnDef.caption
        };
    }
};

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

//Корневая панель выдачи сменного задания на участок
const MechRecCostJobs = () => {
    //Состояние диалога включения в задание
    const [showInclude, setShowInclude] = useState(false);

    //Состояние информации о сменном задании
    const [state, setState] = useCostJobs();

    //Состояние таблицы сменных заданий
    const [costJobsSpecs, setCostJobsSpecs, issueCostJobsSpecs] = useCostJobsSpecs(state.jobInfo.NRN);

    //Состояние таблицы рабочих
    const [costJobsWorkers, setCostJobsWorkers, includeWorker, excludeWorker] = useCostJobsWorkers(state.jobInfo.NRN);

    //При изменении состояния сортировки операций
    const handleCostJobsSpecOrderChanged = ({ orders }) => setCostJobsSpecs(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));

    //При изменении количества отображаемых страниц операций
    const handleCostJobsSpecPagesCountChanged = () => setCostJobsSpecs(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));

    //При изменении состояния сортировки рабочих
    const handleCostJobsWorkersOrderChanged = ({ orders }) => setCostJobsWorkers(pv => ({ ...pv, orders: [...orders], pageNumber: 1, reload: true }));

    //При изменении количества отображаемых страниц рабочих
    const handleCostJobsWorkersPagesCountChanged = () => setCostJobsWorkers(pv => ({ ...pv, pageNumber: pv.pageNumber + 1, reload: true }));

    //При исключении рабочих из строки сменного задания
    const handleCostJobsSpecExcludeWorker = () => {
        //Делаем асинхронно, чтобы при ошибке ничего не обновлять
        const excludeAsync = async () => {
            //Исключаем рабочего из строки сменного задания
            try {
                await excludeWorker({
                    NFCJOBSSP: costJobsSpecs.selectedRow.NRN
                });
                //Необходимо обновить данные
                setCostJobsSpecs(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
                setCostJobsWorkers(pv => ({ ...pv, selectedRows: [], pageNumber: 1, reload: true }));
            } catch (e) {
                throw new Error(e.message);
            }
        };
        //Исключаем рабочего асинхронно
        excludeAsync();
    };

    //Выдача задания операции
    const handleCostJobsSpecIssue = () => {
        //Делаем асинхронно, чтобы при ошибке ничего не обновлять
        const issueAsync = async () => {
            //Включаем рабочих в операции
            try {
                await issueCostJobsSpecs({ NFCJOBS: state.jobInfo.NRN, NCOEFF: state.coeff });
                //Необходимо обновить данные
                setCostJobsSpecs(pv => ({ ...pv, selectedRow: {}, pageNumber: 1, reload: true }));
                setCostJobsWorkers(pv => ({ ...pv, selectedRows: [], pageNumber: 1, reload: true }));
            } catch (e) {
                throw new Error(e.message);
            }
        };
        //Выдаем задание асинхронно
        issueAsync();
    };

    //При изменение состояния выбора
    const handleSelectChange = prms => {
        //Выбранный элемент
        let selectedRow = null;
        //Буфер для выбранных рабочих
        let selectedWorkers = [];
        //Индекс рабочего в списке выбранных
        let workerIndex = null;
        //Исходим от раздела
        switch (prms.SUNIT) {
            //Сменное задание
            case UNIT_COST_JOBS_SPECS:
                //Определяем это новое отмеченное сменное задание или сброс старого
                selectedRow = costJobsSpecs.selectedRow.NRN ? (costJobsSpecs.selectedRow.NRN === prms.NRN ? null : prms.NRN) : prms.NRN;
                //Актуализируем строки
                setCostJobsSpecs(pv => ({
                    ...pv,
                    selectedRow: selectedRow
                        ? {
                              NRN: selectedRow,
                              NPERFORM_FACT: prms.NPERFORM_FACT,
                              NRESOURCE_NUMB: prms.NRESOURCE_NUMB,
                              NQUANT_PLAN: prms.NQUANT_PLAN,
                              SWORKERS_LIST: prms.SWORKERS_LIST
                          }
                        : { NRN: null, NPERFORM_FACT: null, NRESOURCE_NUMB: null, NQUANT_PLAN: null, SWORKERS_LIST: [] }
                }));
                //Выходим
                break;
            //Рабочие центры
            case UNIT_WORKERS:
                //Инициализируем рабочими центрами
                selectedWorkers = costJobsWorkers.selectedRows || [];
                //Определяем индекс элемента в массиве
                workerIndex = selectedWorkers.indexOf(prms.NRN);
                //Если такого рег. номера нет в списке - добавляем, иначе удаляем
                workerIndex > -1 ? selectedWorkers.splice(workerIndex, 1) : selectedWorkers.push(prms.NRN);
                //Актуализируем строки
                setCostJobsWorkers(pv => ({ ...pv, selectedRows: selectedWorkers }));
                //Выходим
                break;
            default:
                return;
        }
    };

    //При открытии/закрытии диалога добавления
    const handleShowIncludeChange = needShow => setShowInclude(needShow);

    //При изменении коэффициент выполнения норм
    const handleIssueCoeffChange = e => {
        isValidIssueCoeff(e.target.value) ? setState(pv => ({ ...pv, coeff: e.target.value })) : null;
    };

    return (
        <Box p={2}>
            {state.loaded ? (
                <Box sx={STYLES.CONTAINER}>
                    <Typography
                        sx={STYLES.MAIN_HEADER}
                        variant={"h6"}
                    >{`Сменное задание №${state.jobInfo.SDOC_NUMB} на ${state.jobInfo.SPERIOD}`}</Typography>
                    <Typography sx={STYLES.SUB_HEADER} variant={"h6"}>{`${state.jobInfo.SSUBDIV}`}</Typography>
                    <Box sx={STYLES.CONTAINER}>
                        <Grid container spacing={2}>
                            <Grid item sx={STYLES.CONTAINER} xs={6}>
                                <Typography sx={STYLES.TABLE_HEADER} variant={"h6"} color={"text.secondary"}>
                                    Сменное задание
                                </Typography>
                                {costJobsWorkers.dataLoaded ? (
                                    <>
                                        <Box sx={STYLES.TABLE_BUTTONS}>
                                            <Stack direction={"row"} spacing={1}>
                                                <Tooltip
                                                    title={
                                                        state.jobInfo.NHAVE_NOTE
                                                            ? "Сменное задание имеет строку с примечанием"
                                                            : "Коэффициент выполнения норм"
                                                    }
                                                >
                                                    <TextField
                                                        name="editIssueValue"
                                                        variant="outlined"
                                                        sx={{ width: "68px" }}
                                                        inputProps={{ sx: { padding: "4.2px 14px" } }}
                                                        size="small"
                                                        value={state.coeff}
                                                        onChange={handleIssueCoeffChange}
                                                        disabled={state.jobInfo.NHAVE_NOTE}
                                                    />
                                                </Tooltip>
                                                <Tooltip
                                                    title={
                                                        state.jobInfo.NHAVE_NOTE
                                                            ? "Сменное задание имеет строку с примечанием"
                                                            : !hasValue(state.coeff)
                                                            ? "Не указано значение коэффициент выполнения норм"
                                                            : null
                                                    }
                                                >
                                                    <Box>
                                                        <Button
                                                            variant="contained"
                                                            size="small"
                                                            disabled={state.jobInfo.NHAVE_NOTE || !hasValue(state.coeff)}
                                                            onClick={handleCostJobsSpecIssue}
                                                        >
                                                            Выдать задания
                                                        </Button>
                                                    </Box>
                                                </Tooltip>
                                            </Stack>
                                        </Box>
                                        <Box sx={STYLES.TABLE}>
                                            <P8PDataGrid
                                                {...P8P_DATA_GRID_CONFIG_PROPS}
                                                containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER(costJobsSpecs.morePages), elevation: 4 }}
                                                columnsDef={costJobsSpecs.columnsDef}
                                                rows={costJobsSpecs.rows}
                                                size={P8P_DATA_GRID_SIZE.SMALL}
                                                morePages={costJobsSpecs.morePages}
                                                reloading={costJobsSpecs.reload}
                                                onOrderChanged={handleCostJobsSpecOrderChanged}
                                                onPagesCountChanged={handleCostJobsSpecPagesCountChanged}
                                                dataCellRender={prms =>
                                                    dataCellRender({
                                                        ...prms,
                                                        handleSelectChange,
                                                        sUnit: UNIT_COST_JOBS_SPECS,
                                                        selectedJobSpec: costJobsSpecs.selectedRow
                                                    })
                                                }
                                                headCellRender={prms => headCellRender({ ...prms })}
                                                fixedHeader={costJobsSpecs.fixedHeader}
                                                fixedColumns={costJobsSpecs.fixedColumns}
                                            />
                                        </Box>
                                    </>
                                ) : null}
                            </Grid>
                            <Grid item sx={STYLES.CONTAINER} xs={6}>
                                <Typography sx={STYLES.TABLE_HEADER} variant={"h6"} color={"text.secondary"}>
                                    Рабочие
                                </Typography>
                                {costJobsWorkers.dataLoaded ? (
                                    <>
                                        <Box sx={STYLES.TABLE_BUTTONS}>
                                            <Stack direction={"row"} spacing={1}>
                                                <Button
                                                    variant="contained"
                                                    size="small"
                                                    disabled={!(costJobsSpecs.selectedRow.NRESOURCE_NUMB === costJobsWorkers.selectedRows.length)}
                                                    onClick={() => handleShowIncludeChange(true)}
                                                >
                                                    Включить в задание
                                                </Button>
                                                <Button
                                                    variant="contained"
                                                    size="small"
                                                    disabled={!costJobsSpecs.selectedRow.NRN || !costJobsSpecs.selectedRow.NPERFORM_FACT}
                                                    onClick={handleCostJobsSpecExcludeWorker}
                                                >
                                                    Исключить из задания
                                                </Button>
                                            </Stack>
                                        </Box>
                                        <Box sx={STYLES.TABLE}>
                                            <P8PDataGrid
                                                {...P8P_DATA_GRID_CONFIG_PROPS}
                                                containerComponentProps={{ sx: STYLES.DATA_GRID_CONTAINER(costJobsWorkers.morePages), elevation: 4 }}
                                                columnsDef={costJobsWorkers.columnsDef}
                                                rows={costJobsWorkers.rows}
                                                size={P8P_DATA_GRID_SIZE.SMALL}
                                                morePages={costJobsWorkers.morePages}
                                                reloading={costJobsWorkers.reload}
                                                onOrderChanged={handleCostJobsWorkersOrderChanged}
                                                onPagesCountChanged={handleCostJobsWorkersPagesCountChanged}
                                                dataCellRender={prms =>
                                                    dataCellRender({
                                                        ...prms,
                                                        handleSelectChange,
                                                        sUnit: UNIT_WORKERS,
                                                        selectedWorkerRows: costJobsWorkers.selectedRows,
                                                        selectedJobSpec: costJobsSpecs.selectedRow
                                                    })
                                                }
                                                headCellRender={prms => headCellRender({ ...prms })}
                                                fixedHeader={true}
                                            />
                                        </Box>
                                    </>
                                ) : null}
                            </Grid>
                        </Grid>
                    </Box>
                </Box>
            ) : null}
            {showInclude ? (
                <CostJobsSpecsInclude
                    includePrms={{
                        NFCJOBSSP: costJobsSpecs.selectedRow.NRN,
                        SELECTED_WORKERS: costJobsWorkers.selectedRows,
                        NQUANT_PLAN: costJobsSpecs.selectedRow.NQUANT_PLAN
                    }}
                    setShowInclude={setShowInclude}
                    setCostJobsSpecs={setCostJobsSpecs}
                    setCostJobsWorkers={setCostJobsWorkers}
                    includeWorker={includeWorker}
                />
            ) : null}
        </Box>
    );
};

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

export { MechRecCostJobs };
