/*
    Парус 8 - Панели мониторинга - Редактор панелей
    Компоненты: Форма (редактор настроек)
*/

//TODO: Контроль уникальности имени элемента формы

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

import React, { useEffect, useState, useContext } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import {
    TextField,
    Button,
    Icon,
    Select,
    Menu,
    MenuItem,
    FormControl,
    InputLabel,
    FormControlLabel,
    Switch,
    Chip,
    Stack,
    InputAdornment,
    IconButton
} from "@mui/material"; //Интерфейсные элементы
import { ApplicationCtx } from "../../../../context/application"; //Контекст приложения
import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; //Контейнер редактора
import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Заголовок раздела редактора
import { P8PConfigDialog } from "../../../../components/editors/p8p_config_dialog"; //Диалог настройки
import { STYLES as COMMON_STYLES } from "../../../../components/editors/p8p_editors_common"; //Общие ресурсы редакторов
import { TITLES } from "../../../../../app.text"; //Общие текстовые ресурсы
import { ITEM_SHAPE, ITEM_INITIAL, ITEMS_INITIAL, ORIENTATION, isItemOkDisabled } from "./common"; //Общие ресурсы и константы формы

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

//Стили
const STYLES = {
    CHIP_ITEM: { ...COMMON_STYLES.CHIP(true, false) }
};

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

//Редактор элемента
const ItemEditor = ({ item = null, valueProviders = {}, onOk = null, onCancel = null } = {}) => {
    //Собственное состояние - параметры элемента формы
    const [state, setState] = useState({ ...ITEM_INITIAL, ...item });

    //Собственное состояние - элемент привязки меню выбора источника
    const [valueProvidersMenuAnchorEl, setValueProvidersMenuAnchorEl] = useState(null);

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

    //При закрытии редактора с сохранением
    const handleOk = () => onOk && onOk({ ...state });

    //При закрытии редактора с отменой
    const handleCancel = () => onCancel && onCancel();

    //При изменении параметра элемента
    const handleChange = e => setState(pv => ({ ...pv, [e.target.id]: e.target.value }));

    //При нажатии на очистку раздела
    const handleClearUnitClick = () =>
        setState(pv => ({
            ...pv,
            unitCode: "",
            unitName: "",
            showMethod: "",
            showMethodName: "",
            parameter: "",
            inputParameter: "",
            outputParameter: ""
        }));

    //При нажатии на выбор раздела
    const handleSelectUnitClick = () => {
        pOnlineShowDictionary({
            unitCode: "Units",
            showMethod: "methods",
            inputParameters: [
                { name: "pos_unit_name", value: state.unitName },
                { name: "pos_method_name", value: state.showMethodName }
            ],
            callBack: res =>
                res.success &&
                setState(pv => ({
                    ...pv,
                    unitCode: res.outParameters.unit_code,
                    unitName: res.outParameters.unit_name,
                    showMethod: res.outParameters.method_code,
                    showMethodName: res.outParameters.method_name,
                    parameter: "",
                    inputParameter: "",
                    outputParameter: ""
                }))
        });
    };

    //При нажатии на выбор параметра метода вызова
    const handleSelectUnitParameterClick = () => {
        state.unitCode &&
            state.showMethod &&
            pOnlineShowDictionary({
                unitCode: "UnitParams",
                showMethod: "main",
                inputParameters: [
                    { name: "in_UNITCODE", value: state.unitCode },
                    { name: "in_PARENT_METHOD_CODE", value: state.showMethod },
                    { name: "in_PARAMNAME", value: state.parameter }
                ],
                callBack: res =>
                    res.success &&
                    setState(pv => ({
                        ...pv,
                        parameter: res.outParameters.out_PARAMNAME,
                        inputParameter: res.outParameters.out_IN_CODE,
                        outputParameter: res.outParameters.out_OUT_CODE
                    }))
            });
    };

    //Открытие/сокрытие меню выбора источника
    const toggleValueProvidersMenu = target => setValueProvidersMenuAnchorEl(target instanceof Element ? target : null);

    //При очистке значения/связывания параметра
    const handleParamClearClick = () => setState(pv => ({ ...pv, name: "" }));

    //При отображении меню связывания параметра с поставщиком данных
    const handleParamLinkMenuClick = e => setValueProvidersMenuAnchorEl(e.currentTarget);

    //При выборе элемента меню связывания аргумента с поставщиком данных
    const handleParamLinkClick = valueSource => {
        //Устанавливаем выбранный параметр
        setState(pv => ({ ...pv, name: valueSource }));
        //Закрываем меню
        toggleValueProvidersMenu();
    };

    //Список значений
    const values = Object.keys(valueProviders);

    //Наличие значений
    const isValues = values && values.length > 0 ? true : false;

    //Меню привязки к поставщикам значений
    const valueProvidersMenu = isValues && (
        <Menu anchorEl={valueProvidersMenuAnchorEl} open={Boolean(valueProvidersMenuAnchorEl)} onClose={toggleValueProvidersMenu}>
            {values.map((value, i) => (
                <MenuItem key={i} onClick={() => handleParamLinkClick(value)}>
                    {value}
                </MenuItem>
            ))}
        </Menu>
    );

    //Формирование представления
    return (
        <P8PConfigDialog
            title={`${item ? TITLES.UPDATE : TITLES.INSERT} элемента`}
            onOk={handleOk}
            onCancel={handleCancel}
            okDisabled={isItemOkDisabled(state)}
        >
            <Stack direction={"column"} spacing={1}>
                {valueProvidersMenu}
                <TextField
                    type={"text"}
                    variant={"standard"}
                    value={state.name}
                    label={"Имя"}
                    id={"name"}
                    required={true}
                    onChange={handleChange}
                    InputProps={{
                        readOnly: true,
                        endAdornment: (
                            <InputAdornment position="end">
                                <IconButton onClick={handleParamClearClick}>
                                    <Icon>clear</Icon>
                                </IconButton>
                                {isValues && (
                                    <IconButton onClick={handleParamLinkMenuClick}>
                                        <Icon>settings_ethernet</Icon>
                                    </IconButton>
                                )}
                            </InputAdornment>
                        )
                    }}
                />
                <TextField type={"text"} variant={"standard"} value={state.caption} label={"Приглашение"} id={"caption"} onChange={handleChange} />
                <TextField
                    type={"text"}
                    variant={"standard"}
                    value={state.unitName}
                    label={"Раздел"}
                    InputLabelProps={{ shrink: state.unitName ? true : false }}
                    InputProps={{
                        readOnly: true,
                        endAdornment: (
                            <InputAdornment position="end">
                                <IconButton onClick={handleClearUnitClick}>
                                    <Icon>clear</Icon>
                                </IconButton>
                                <IconButton onClick={handleSelectUnitClick}>
                                    <Icon>list</Icon>
                                </IconButton>
                            </InputAdornment>
                        )
                    }}
                />
                <TextField
                    type={"text"}
                    variant={"standard"}
                    value={state.showMethodName}
                    label={"Метод вызова"}
                    InputLabelProps={{ shrink: state.showMethodName ? true : false }}
                    InputProps={{ readOnly: true }}
                />
                <TextField
                    type={"text"}
                    variant={"standard"}
                    value={state.parameter}
                    label={"Параметр"}
                    InputLabelProps={{ shrink: state.parameter ? true : false }}
                    InputProps={{
                        readOnly: true,
                        endAdornment: (
                            <InputAdornment position="end">
                                <IconButton onClick={handleSelectUnitParameterClick}>
                                    <Icon>list</Icon>
                                </IconButton>
                            </InputAdornment>
                        )
                    }}
                />
            </Stack>
        </P8PConfigDialog>
    );
};

//Контроль свойств - редактор элемента
ItemEditor.propTypes = {
    item: ITEM_SHAPE,
    valueProviders: PropTypes.object,
    onOk: PropTypes.func,
    onCancel: PropTypes.func
};

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

//Форма (редактор настроек)
const FormEditor = ({
    id,
    title = "",
    orientation = ORIENTATION.V,
    autoApply = false,
    items = ITEMS_INITIAL,
    valueProviders = {},
    onSettingsChange = null
} = {}) => {
    //Собственное состояние - текущие настройки
    const [settings, setSettings] = useState(null);

    //Собственное состояние - редактор элементов формы
    const [itemEditor, setItemEditor] = useState({ display: false, index: null });

    //При изменении значения настройки
    const handleChange = e => setSettings({ ...settings, [e.target.name]: e.target.type === "checkbox" ? e.target.checked : e.target.value });

    //При добавлении нового элемента
    const handleItemAdd = () => setItemEditor({ display: true, index: null });

    //При нажатии на элемент
    const handleItemClick = i => setItemEditor({ display: true, index: i });

    //При удалении элемента
    const handleItemDelete = i => {
        const items = [...settings.items];
        items.splice(i, 1);
        setSettings(pv => ({ ...pv, items }));
    };

    //При сохранении изменений элемента
    const handleItemSave = item => {
        const items = [...settings.items];
        itemEditor.index == null ? items.push({ ...item }) : (items[itemEditor.index] = { ...item });
        setSettings(pv => ({ ...pv, items }));
        setItemEditor({ display: false, index: null });
    };

    //При отмене сохранения изменений элемента
    const handleItemCancel = () => setItemEditor({ display: false, index: null });

    //При сохранении настроек
    const handleSave = (closeEditor = false) => onSettingsChange && onSettingsChange({ id, settings, closeEditor });

    //При изменении компонента
    useEffect(() => {
        settings?.id != id && setSettings({ id, title, orientation, autoApply, items });
    }, [settings, id, title, orientation, autoApply, items]);

    //Формирование представления
    return (
        settings && (
            <P8PEditorBox title={"Параметры формы"} onSave={handleSave}>
                {itemEditor.display && (
                    <ItemEditor
                        item={itemEditor.index !== null ? { ...settings.items[itemEditor.index] } : null}
                        valueProviders={valueProviders}
                        onCancel={handleItemCancel}
                        onOk={handleItemSave}
                    />
                )}
                <P8PEditorSubHeader title={"Общие"} />
                <TextField type={"text"} variant={"standard"} value={settings.title} label={"Заголовок"} name={"title"} onChange={handleChange} />
                <FormControl variant={"standard"}>
                    <InputLabel id={"orientation-label"}>Ориентация</InputLabel>
                    <Select
                        name={"orientation"}
                        value={settings.orientation}
                        labelId={"orientation-label"}
                        label={"Ориентация"}
                        onChange={handleChange}
                    >
                        <MenuItem value={ORIENTATION.V}>Вертикально</MenuItem>
                        <MenuItem value={ORIENTATION.H}>Горизонтально</MenuItem>
                    </Select>
                </FormControl>
                <FormControlLabel
                    control={<Switch name={"autoApply"} checked={settings.autoApply} onChange={handleChange} />}
                    label={"Автоподтверждение"}
                />
                <P8PEditorSubHeader title={"Элементы"} />
                {Array.isArray(settings?.items) &&
                    settings.items.length > 0 &&
                    settings.items.map((item, i) => (
                        <Chip
                            key={i}
                            label={item.caption}
                            variant={"outlined"}
                            onClick={() => handleItemClick(i)}
                            onDelete={() => handleItemDelete(i)}
                            sx={STYLES.CHIP_ITEM}
                        />
                    ))}
                <Button startIcon={<Icon>add</Icon>} onClick={handleItemAdd}>
                    Добавить элемент
                </Button>
            </P8PEditorBox>
        )
    );
};

//Контроль свойств компонента - Форма (редактор настроек)
FormEditor.propTypes = {
    id: PropTypes.string.isRequired,
    title: PropTypes.string,
    orientation: PropTypes.oneOf(Object.values(ORIENTATION)),
    autoApply: PropTypes.bool,
    items: PropTypes.arrayOf(ITEM_SHAPE),
    valueProviders: PropTypes.object,
    onSettingsChange: PropTypes.func
};

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

export default FormEditor;
