import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { CkRichEditor } from '../UI/inputs/richEditors/CkRichEditor';
import { makeStyles, TextField, LinearProgress } from '@material-ui/core';
import { Field, Form } from '../utilities/form';
import { FluentTextFieldAutoComplete } from '../UI/inputs/textField/FluentTextFieldAutoComplete';
import { useTranslation } from 'react-i18next';
import { useActionState } from '../hooks/useActions';
import { constructBusinessObjectArrFromTree } from '../utilities/tree/TreeUtilities';
import { LayoutUnit } from '../layout/LayoutUnit';
import { UdpEnums } from '../enums/unitySystemEnums';
import { useHandleAxiosSnackbar } from '../utilities/apiHelpers';
import { useUser } from '../utilities/auth/useUser';
import { differenceWith } from 'lodash-es';
import { executeQueryAdHoc, getBaseMethod, executeQueryWithParameters } from '../udp/utilities/methodUtils';
import { ShortcutContentFinder } from '../udp/ShortcutContent/ShortcutContentFinder';
import { AmbientCard } from '../UI/surfaces/cards/AmbientCard';
import { useShellStore } from '../stores/shellStore';
import { getSearchObject } from '../utilities/search/SearchUtilities';
const useStyles = makeStyles((theme) => {
    var _a;
    return ({
        root: {},
        editor: {
            '& .ck-editor__main > .ck-editor__editable_inline': {
                backgroundColor: ((_a = theme === null || theme === void 0 ? void 0 : theme.getThemeData()) === null || _a === void 0 ? void 0 : _a.mode) === 'dark'
                    ? theme.palette.grey[800]
                    : theme.palette.grey[100]
            }
        },
        row: {
            display: 'flex',
            justifyContent: 'space-between'
        },
        input: {
            height: 34,
            padding: 0
        },
        formTextInput: {
            fontSize: 14
        },
        labelRoot: {
            fontSize: 14
        }
    });
});
export const NotesScreen = (props) => {
    const { formRef, onSubmit, shortcutContentFinderEnabled, id, viewOnly, reloadNotes } = props;
    const [note, setNote] = useState('');
    const [typeOptions, setTypeOptions] = useState([]);
    const [templateOptions, setTemplateOptions] = useState([]);
    const [noteId, setNoteId] = useState(id || '');
    const [existingNoteFiledFor, setExistingNoteFiledFor] = useState([]);
    const [existingNoteObj, setExistingNoteObj] = useState(null);
    const [loading, setLoading] = useState(false);
    const classes = useStyles(props);
    const { t } = useTranslation();
    const actionState = useActionState();
    const shellHidden = useShellStore((state) => state.shellHidden);
    const { menuListState, catalogPromotedEntities } = actionState;
    const { handleSuccessSnackbar, handleErrorSnackbar } = useHandleAxiosSnackbar();
    const user = useUser();
    const editorRef = useRef(null);
    const selectedMenu = useMemo(() => {
        if (menuListState.menuList.length) {
            return menuListState.menuList[menuListState.selectedMenuIndex] || null;
        }
        return null;
    }, [menuListState]);
    const noteGetFullApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note, 'unityBaseGetFullMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const noteTypeSearchApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note_Type, 'unityBaseSearchMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const noteTemplateSearchApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note_Template, 'unityBaseSearchMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const createNoteApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note, 'unityBaseCreateMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const updateNoteApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note, 'unityBaseUpdateMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const createNoteFiledForApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note_Filed_For, 'unityBaseCreateMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const deleteNoteFiledForApiMethod = useMemo(() => {
        return getBaseMethod(UdpEnums.Udp_Note_Filed_For, 'unityBaseDeleteMethod', catalogPromotedEntities);
    }, [catalogPromotedEntities]);
    const disabled = useMemo(() => {
        return viewOnly;
    }, [viewOnly]);
    const handleSaveNote = useCallback(async (values) => {
        var _a;
        let response = null;
        const data = {
            requestBody: {
                tenantId: user === null || user === void 0 ? void 0 : user.currentTenantId,
                typeCode: (_a = values === null || values === void 0 ? void 0 : values.type) === null || _a === void 0 ? void 0 : _a.code,
                subject: values === null || values === void 0 ? void 0 : values.subject,
                content: values === null || values === void 0 ? void 0 : values.note,
                unityUserId: user === null || user === void 0 ? void 0 : user.id,
                userDisplayName: `${user === null || user === void 0 ? void 0 : user.firstName} ${user === null || user === void 0 ? void 0 : user.familyName}`
            }
        };
        if (noteId) {
            if (updateNoteApiMethod) {
                // Set the url parameter for updating note
                data['{iD}'] = noteId;
                response = await executeQueryWithParameters({ data }, updateNoteApiMethod.apiMethodId).catch((e) => handleErrorSnackbar(e, 'Could not Update Note'));
            }
            else {
                handleErrorSnackbar(null, 'Update Note Method Not Promoted');
            }
        }
        else {
            if (createNoteApiMethod) {
                response = await executeQueryWithParameters({ data }, createNoteApiMethod.apiMethodId).catch((e) => handleErrorSnackbar(e, 'Could not Save Note'));
            }
            else {
                handleErrorSnackbar(null, 'Create Note Method Not Promoted');
            }
        }
        if ((response === null || response === void 0 ? void 0 : response.status) === 200) {
            if (!noteId) {
                setNoteId(response.data.id || '');
                handleSuccessSnackbar('Note Saved');
            }
            else {
                handleSuccessSnackbar('Note Updated');
            }
            if (reloadNotes) {
                reloadNotes();
            }
            return response.data.id || noteId;
        }
        return noteId;
    }, [
        createNoteApiMethod,
        updateNoteApiMethod,
        noteId,
        setNoteId,
        handleErrorSnackbar,
        handleSuccessSnackbar,
        user,
        reloadNotes
    ]);
    const noteFiledForToComparator = (nftc1, nftc2) => {
        return (nftc1 === null || nftc1 === void 0 ? void 0 : nftc1.value) === (nftc2 === null || nftc2 === void 0 ? void 0 : nftc2.value);
    };
    const handleNoteFiledFor = useCallback(async (values, notedIdToFileFor) => {
        // Get the noteFiledFor objects to delete
        const noteFiledForToDelete = differenceWith(existingNoteFiledFor, values === null || values === void 0 ? void 0 : values.fileTo, noteFiledForToComparator);
        // Get the noteFiledFor objects to create
        const noteFiledForToCreate = differenceWith(values === null || values === void 0 ? void 0 : values.fileTo, existingNoteFiledFor, noteFiledForToComparator);
        if (notedIdToFileFor) {
            if (deleteNoteFiledForApiMethod) {
                const deletedPromises = [];
                noteFiledForToDelete.forEach((nftd) => {
                    const data = {};
                    data['{noteID}'] = notedIdToFileFor;
                    data['{entityBusinessKey}'] = nftd.value;
                    deletedPromises.push(executeQueryWithParameters({ data }, deleteNoteFiledForApiMethod.apiMethodId));
                });
                await Promise.all(deletedPromises.map((p) => p.catch((e) => e))).then((responses) => {
                    if (responses.length !== deletedPromises.length) {
                        console.warn(`Not all Note Filed For deleted`);
                    }
                });
            }
            else {
                handleErrorSnackbar(null, 'Delete Note Filed For Method Not Promoted');
            }
            if (createNoteFiledForApiMethod) {
                const createdPromises = [];
                noteFiledForToCreate.forEach((nftc) => {
                    const data = {
                        requestBody: {
                            noteId: notedIdToFileFor,
                            entityBusinessKey: nftc.value
                        }
                    };
                    createdPromises.push(executeQueryWithParameters({ data }, createNoteFiledForApiMethod.apiMethodId));
                });
                await Promise.all(createdPromises.map((p) => p.catch((e) => e))).then((responses) => {
                    responses.forEach((response) => {
                        if (response.status === 200) {
                            const entityBusinessKey = response.data.entityBusinessKey;
                            const matchingNoteFiledFor = noteFiledForToCreate.find((nftc) => nftc.value === entityBusinessKey);
                            if (!matchingNoteFiledFor) {
                                console.warn(`Note Filed For not created for all file to entities`);
                            }
                        }
                    });
                });
                setExistingNoteFiledFor(values === null || values === void 0 ? void 0 : values.fileTo);
            }
            else {
                handleErrorSnackbar(null, 'Create Note Filed For Method Not Promoted');
            }
        }
    }, [
        createNoteFiledForApiMethod,
        deleteNoteFiledForApiMethod,
        handleErrorSnackbar,
        existingNoteFiledFor,
        setExistingNoteFiledFor
    ]);
    const handleOnSubmit = useCallback(async (values) => {
        if (onSubmit) {
            onSubmit(Object.assign({ note }, values));
        }
        else {
            const notedIdToFileFor = await handleSaveNote(Object.assign({ note }, values));
            await handleNoteFiledFor(Object.assign({ note }, values), notedIdToFileFor);
        }
    }, [note, onSubmit, handleSaveNote, handleNoteFiledFor]);
    const handleTextEditorChange = (note) => {
        setNote(note);
    };
    const onTemplateChange = useCallback((value) => {
        var _a, _b, _c, _d;
        (_b = (_a = formRef === null || formRef === void 0 ? void 0 : formRef.current) === null || _a === void 0 ? void 0 : _a.form) === null || _b === void 0 ? void 0 : _b.change('subject', (value === null || value === void 0 ? void 0 : value.subject) || '');
        const type = typeOptions.find((option) => option.code === value.typeCode);
        (_d = (_c = formRef === null || formRef === void 0 ? void 0 : formRef.current) === null || _c === void 0 ? void 0 : _c.form) === null || _d === void 0 ? void 0 : _d.change('type', type || null);
        setNote((value === null || value === void 0 ? void 0 : value.content) || '');
    }, [setNote, formRef, typeOptions]);
    const handleShortcutOnSelect = useCallback((shortcutContent) => {
        var _a, _b, _c;
        (_b = (_a = editorRef === null || editorRef === void 0 ? void 0 : editorRef.current) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.change((writer) => {
            var _a, _b, _c, _d, _e, _f, _g, _h;
            const insertPosition = (_d = (_c = (_b = (_a = editorRef === null || editorRef === void 0 ? void 0 : editorRef.current) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.document) === null || _c === void 0 ? void 0 : _c.selection) === null || _d === void 0 ? void 0 : _d.getFirstPosition();
            writer.remove((_h = (_g = (_f = (_e = editorRef === null || editorRef === void 0 ? void 0 : editorRef.current) === null || _e === void 0 ? void 0 : _e.model) === null || _f === void 0 ? void 0 : _f.document) === null || _g === void 0 ? void 0 : _g.selection) === null || _h === void 0 ? void 0 : _h.getFirstRange());
            writer.insertText(shortcutContent, insertPosition);
        });
        setNote((_c = editorRef === null || editorRef === void 0 ? void 0 : editorRef.current) === null || _c === void 0 ? void 0 : _c.getData());
    }, [editorRef, setNote]);
    const fileToOptions = useMemo(() => {
        let options = [];
        if (selectedMenu) {
            options = constructBusinessObjectArrFromTree(selectedMenu);
        }
        return options;
    }, [selectedMenu]);
    useEffect(() => {
        // TODO: use getAll noteTypes
        const getTypeOptions = async () => {
            var _a;
            let options = [];
            if (noteTypeSearchApiMethod) {
                const filterElements = [];
                const searchObject = getSearchObject(filterElements, 1, 200, true);
                const data = { data: searchObject };
                const typesResponse = await executeQueryAdHoc(data, noteTypeSearchApiMethod.apiMethodId);
                if ((typesResponse === null || typesResponse === void 0 ? void 0 : typesResponse.status) === 200) {
                    options = (_a = typesResponse.data) === null || _a === void 0 ? void 0 : _a.pageList;
                }
            }
            setTypeOptions(options);
        };
        getTypeOptions();
    }, [noteTypeSearchApiMethod, setTypeOptions, user]);
    useEffect(() => {
        // TODO: use getAll noteTemplates
        const getTemplateOptions = async () => {
            var _a;
            let options = [];
            if (noteTemplateSearchApiMethod) {
                const filterElements = [];
                const searchObject = getSearchObject(filterElements, 1, 200, true);
                const data = { data: searchObject };
                const templatesResponse = await executeQueryAdHoc(data, noteTemplateSearchApiMethod.apiMethodId);
                if ((templatesResponse === null || templatesResponse === void 0 ? void 0 : templatesResponse.status) === 200) {
                    options = (_a = templatesResponse.data) === null || _a === void 0 ? void 0 : _a.pageList;
                }
            }
            setTemplateOptions(options);
        };
        getTemplateOptions();
    }, [noteTemplateSearchApiMethod, setTemplateOptions, user]);
    useEffect(() => {
        const getExistingNote = async () => {
            let existingNoteObj = null;
            const data = {};
            if (noteGetFullApiMethod) {
                setLoading(true);
                data['{iD}'] = id;
                const noteResponse = await executeQueryWithParameters({ data }, noteGetFullApiMethod.apiMethodId).catch((e) => {
                    console.error(e);
                    setLoading(false);
                });
                if ((noteResponse === null || noteResponse === void 0 ? void 0 : noteResponse.status) === 200) {
                    existingNoteObj = noteResponse.data;
                }
            }
            setExistingNoteObj(existingNoteObj);
            setNote(existingNoteObj === null || existingNoteObj === void 0 ? void 0 : existingNoteObj.content);
            setLoading(false);
        };
        if (id) {
            getExistingNote();
        }
    }, [id, noteGetFullApiMethod]);
    useEffect(() => {
        var _a, _b;
        if (!existingNoteObj || !(fileToOptions === null || fileToOptions === void 0 ? void 0 : fileToOptions.length)) {
            return;
        }
        const initialFileTos = fileToOptions.filter((option) => {
            return existingNoteObj.noteFiledFor.find((nff) => option.value === nff.entityBusinessKey);
        });
        setExistingNoteFiledFor(initialFileTos);
        (_b = (_a = formRef === null || formRef === void 0 ? void 0 : formRef.current) === null || _a === void 0 ? void 0 : _a.form) === null || _b === void 0 ? void 0 : _b.change('fileTo', initialFileTos);
    }, [existingNoteObj, fileToOptions, formRef]);
    useEffect(() => {
        var _a, _b;
        if (!existingNoteObj || !(typeOptions === null || typeOptions === void 0 ? void 0 : typeOptions.length)) {
            return;
        }
        const initialType = typeOptions.find((option) => option.code === existingNoteObj.typeCode);
        (_b = (_a = formRef === null || formRef === void 0 ? void 0 : formRef.current) === null || _a === void 0 ? void 0 : _a.form) === null || _b === void 0 ? void 0 : _b.change('type', initialType || null);
    }, [existingNoteObj, typeOptions, formRef]);
    useEffect(() => {
        var _a, _b;
        if (!existingNoteObj) {
            return;
        }
        (_b = (_a = formRef === null || formRef === void 0 ? void 0 : formRef.current) === null || _a === void 0 ? void 0 : _a.form) === null || _b === void 0 ? void 0 : _b.change('subject', (existingNoteObj === null || existingNoteObj === void 0 ? void 0 : existingNoteObj.subject) || '');
    }, [existingNoteObj, formRef]);
    return (React.createElement("div", { className: classes.root }, loading && React.createElement(LinearProgress, { color: "secondary" }), React.createElement(AmbientCard, { fullWidth: true, header: true }, React.createElement(Form, { onSubmit: handleOnSubmit, ref: formRef }, React.createElement(Field, { component: FluentTextFieldAutoComplete, label: t('File To'), name: "fileTo", id: "fileTo", fullWidth: true, variant: "outlined", margin: "dense", size: "small", options: fileToOptions || [], optionKey: 'label', required: true, limitTags: !viewOnly ? 2 : -1, isMultiple: true, disabled: disabled }), React.createElement("div", { className: classes.row }, React.createElement("div", { style: { width: '100%' } }, React.createElement(Field, { component: FluentTextFieldAutoComplete, label: t('Type'), name: "type", id: "type", fullWidth: true, variant: "outlined", margin: "dense", size: "small", options: typeOptions || [], optionKey: 'name', required: true, disabled: disabled })), !viewOnly && (React.createElement("div", { style: { width: '100%', marginLeft: 8 } }, React.createElement(Field, { component: FluentTextFieldAutoComplete, label: t('Template'), name: "template", id: "template", fullWidth: true, variant: "outlined", margin: "dense", size: "small", options: templateOptions || [], optionKey: 'name', additionalOnChangeAction: onTemplateChange })))), React.createElement(Field, { component: TextField, label: t('Subject'), name: "subject", id: "subject", fullWidth: true, variant: "outlined", size: "small", margin: "dense", required: true, disabled: disabled, InputProps: {
            classes: {
                root: classes === null || classes === void 0 ? void 0 : classes.input,
                input: classes === null || classes === void 0 ? void 0 : classes.formTextInput
            }
        }, InputLabelProps: {
            classes: {
                root: classes === null || classes === void 0 ? void 0 : classes.labelRoot
            }
        } }), React.createElement(LayoutUnit, { unit: "nudge" }), React.createElement(CkRichEditor, { handleChange: handleTextEditorChange, classes: { editor: classes.editor }, data: note, editorRef: editorRef, isUsingRef: true, readOnly: disabled }))), React.createElement(LayoutUnit, { unit: "nudge" }), shortcutContentFinderEnabled && (React.createElement(AmbientCard, { fullWidth: true, header: true, lastChildBottomPadding: '0px', cardContentHeight: `calc(100vh - ${shellHidden ? '568px' : '623px'})` }, React.createElement(ShortcutContentFinder, { onSelect: handleShortcutOnSelect })))));
};
//# sourceMappingURL=NotesScreen.js.map