import { __awaiter } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
import { Box, Menu, MenuButton, MenuItem, MenuList, Text, Button, Flex, Checkbox, Input, Grid, GridItem, HStack, Portal, } from "@chakra-ui/react";
import { defineComponent } from "@qorebase/app-component";
import React from "react";
import { ChevronCheck, ChevronDown } from "@feedloop/icon";
import { RuntimeContext, useVariablesContext, VariablesProvider, useEvaluateObject, useDisableCondition, } from "@qorebase/app-component";
import useSWR from "swr";
import { tableParams } from "@qorebase/app-runtime/src/utils/tableParams";
import produce from "immer";
import { useFormSubmitHook } from "@qorebase/app-runtime/src/hooks/useFormSubmitHook";
import { useSourceView } from "../../../src/app/hooks/useSourceView";
import format from "@qorebase/app-runtime/src/utils/format";
import InputComponentLabel from "@qorebase/app-runtime/src/components/InputComponentLabel";
const MAX_DISPLAY_OPTION = 5;
const ManyToManyOption = (props) => {
    const label = props.hooks.useTemplate(props.properties.itemLabel);
    const isSelected = props.value.includes(props.item.id);
    const showOption = label.toLowerCase().startsWith(props.search.toLowerCase());
    const onChange = React.useCallback((event) => {
        event.preventDefault();
        props.onChange(isSelected
            ? props.value.filter((id) => id !== props.item.id)
            : props.value.concat(props.item.id));
    }, [props.onChange, isSelected, props.value, props.item.id]);
    return (showOption && (_jsx(MenuItem, Object.assign({ onClick: onChange, backgroundColor: isSelected && "gray.100" }, { children: _jsxs(Flex, { children: [_jsx(Checkbox, { borderColor: "gray", isChecked: isSelected, mr: 2, onChange: onChange }), _jsx(Text, { children: label || props.item.id })] }) }))));
};
const Option = (props) => {
    const label = props.hooks.useTemplate(props.properties.itemLabel);
    const isSelected = props.value === props.item.id;
    const showOption = label.toLowerCase().startsWith(props.search.toLowerCase());
    return (showOption && (_jsx(MenuItem, Object.assign({ onClick: () => props.onChange(props.item.id), backgroundColor: isSelected && "gray.100" }, { children: label || props.item.id }))));
};
const MenuButtonValue = React.forwardRef(function MenuButtonValue(props, ref) {
    const label = props.hooks.useTemplate(props.properties.itemLabel);
    const placeholder = props.hooks.useEvaluate(props.properties.placeholder);
    // @ts-ignore
    const { isDisabled } = useDisableCondition(props.instance);
    return (_jsx(MenuButton, Object.assign({ as: Button, style: {
            border: "1px solid rgb(226, 232, 240)",
            pointerEvents: isDisabled ? "none" : "auto",
            background: isDisabled && "#E7E7E7",
            color: isDisabled && "#A2A2A2",
        }, bgColor: "surface.900", width: "100%", ref: ref, textAlign: "left", borderRadius: "md", variant: "outline", fontWeight: "normal", _focus: { shadow: "0px" }, rightIcon: _jsx(ChevronDown, {}) }, { children: _jsx(Text, Object.assign({ noOfLines: 1, color: isDisabled && "#A2A2A2" }, { children: props.children || label || placeholder })) })));
});
const DropdownRelation = defineComponent({
    name: "Dropdown Relation",
    type: "none",
    icon: "SelectInput",
    group: "input",
    display: "inline",
    defaultProps: {
        label: "Dropdown Relation",
        placeholder: "Placeholder here",
        hidden: false,
        defaultValue: "",
        data: {
            inputID: "DropdownRelation",
            field: { type: "relation", options: {} },
            validation: {
                required: false,
            },
        },
        itemLabel: "",
        options: {
            target: "",
            params: {},
        },
    },
    propDefinition: {
        label: { group: "Design", type: "expression", options: {} },
        placeholder: {
            group: "Design",
            type: "expression",
            options: {},
        },
        hidden: {
            group: "Design",
            type: "boolean",
            options: { format: "boolean" },
        },
        data: {
            group: "Design",
            type: "state",
            options: {
                inputID: "DropdownRelation",
                field: { type: "relation", options: {} },
            },
        },
        defaultValue: {
            group: "Design",
            type: "expression",
            options: {},
        },
        itemLabel: { group: "Design", type: "custom", options: {} },
        options: {
            type: "custom",
            group: "Design",
            options: {},
            style: {
                width: "full-width",
            },
        },
    },
    Editor: () => __awaiter(void 0, void 0, void 0, function* () {
        return {
            itemLabel: (props) => {
                var _a;
                const inputID = (_a = props.values) === null || _a === void 0 ? void 0 : _a.data.inputID;
                const tables = RuntimeContext.useSelectState((state) => state.schema.tables);
                const view = useSourceView();
                const column = React.useMemo(() => view === null || view === void 0 ? void 0 : view.columns.find((column) => column.name === inputID), [view === null || view === void 0 ? void 0 : view.columns, inputID]);
                const targetTable = React.useMemo(() => tables.find((table) => table.name === (column === null || column === void 0 ? void 0 : column.references.targetTable)), [tables, inputID]);
                const items = React.useMemo(() => targetTable === null || targetTable === void 0 ? void 0 : targetTable.columns.map((field) => ({
                    display: `item.${field.name}`,
                    id: `item.${field.name}`,
                })).concat({
                    display: "item.id",
                    id: "item.id",
                }), [targetTable === null || targetTable === void 0 ? void 0 : targetTable.columns]);
                return (_jsx(VariablesProvider, Object.assign({ variables: items }, { children: _jsx(props.PropertyEditor.string, Object.assign({}, props)) })));
            },
            options: (props) => {
                var _a, _b, _c;
                const schema = RuntimeContext.useSelectState((state) => state.schema);
                const selectedColumn = React.useMemo(() => {
                    if (!!props.view && Array.isArray(props.view.columns)) {
                        return props.view.columns.find((col) => { var _a; return col.name === ((_a = props.values) === null || _a === void 0 ? void 0 : _a.data.inputID); });
                    }
                    return;
                }, [props.view, props.values]);
                const selectedSourceTable = React.useMemo(() => {
                    return schema.tables.find((t) => t.name === (selectedColumn === null || selectedColumn === void 0 ? void 0 : selectedColumn.references.targetTable));
                }, [selectedColumn, schema.tables]);
                const optionsMap = React.useMemo(() => {
                    if (!selectedSourceTable)
                        return [];
                    const views = schema.views
                        .filter((view) => view.query.table === selectedSourceTable.name)
                        .map((v) => ({
                        label: v.name,
                        value: v.name,
                    }));
                    const insights = schema.insights
                        .filter((insight) => insight.table === selectedSourceTable.name)
                        .map((v) => ({
                        label: v.name,
                        value: v.name,
                    }));
                    const table = {
                        label: selectedSourceTable.name,
                        value: selectedSourceTable.name,
                    };
                    return [table, ...views, ...insights];
                }, [schema, selectedSourceTable]);
                const [search, setSearch] = React.useState("");
                const isValidTable = React.useMemo(() => {
                    var _a;
                    return (!!selectedSourceTable &&
                        (selectedSourceTable.name === ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target) ||
                            !!schema.views.find((v) => {
                                var _a;
                                return v.query.table === selectedSourceTable.name &&
                                    v.name === ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target);
                            }) ||
                            !!schema.insights.find((i) => {
                                var _a;
                                return i.table === selectedSourceTable.name &&
                                    i.name === ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target);
                            })));
                }, [schema, selectedSourceTable, (_a = props.value) === null || _a === void 0 ? void 0 : _a.target]);
                const handleSearchInput = React.useCallback((e) => setSearch(e.target.value), []);
                const resetSearch = React.useCallback(() => setSearch(""), []);
                const source = React.useMemo(() => {
                    var _a;
                    if (!isValidTable)
                        return;
                    if ((selectedSourceTable === null || selectedSourceTable === void 0 ? void 0 : selectedSourceTable.name) === ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target)) {
                        return selectedSourceTable;
                    }
                    const view = schema.views.find((v) => { var _a; return v.name === ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target); });
                    if (view)
                        return view;
                    const insight = schema.insights.find((i) => { var _a; return i.name === ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target); });
                    if (insight)
                        return insight;
                    return;
                }, [schema, (_b = props.value) === null || _b === void 0 ? void 0 : _b.target, selectedSourceTable, isValidTable]);
                const params = React.useMemo(() => {
                    if (source) {
                        return (tableParams(source).map((param) => ({
                            slug: param.name,
                            type: param.type,
                            required: true,
                        })) || []);
                    }
                    return [];
                }, [source]);
                const handleUpdateParams = React.useCallback((slug, value) => {
                    props.onChange(produce(props.value, (draft) => {
                        if (value === "0") {
                            draft.params[slug] = "";
                        }
                        else {
                            draft.params[slug] = value;
                        }
                    }));
                }, [props.value]);
                React.useEffect(() => {
                    if (!isValidTable && !!selectedSourceTable) {
                        props.onChange({ target: selectedSourceTable.name, params: {} });
                    }
                }, [isValidTable, selectedSourceTable]);
                if (!selectedSourceTable)
                    return null;
                return (_jsxs(Grid, Object.assign({ templateColumns: "repeat(12, 1fr)", py: "10px", gap: 2 }, { children: [_jsx(GridItem, Object.assign({ colSpan: 3, maxW: "full", display: "flex" }, { children: _jsx(HStack, Object.assign({ alignItems: "start", pt: "10px" }, { children: _jsx(Text, Object.assign({ fontSize: "sm", color: "#6F809A", textTransform: "capitalize" }, { children: "Options" })) })) })), _jsx(GridItem, Object.assign({ colSpan: 9, maxW: "full", alignItems: "center", justifyContent: "flex-end" }, { children: _jsxs(Box, { children: [_jsx(Box, { children: _jsxs(Menu, Object.assign({ onClose: resetSearch, isLazy: true }, { children: [_jsx(MenuButton, Object.assign({ as: Button, style: { border: "1px solid rgb(226, 232, 240)" }, bgColor: "surface.900", width: "100%", textAlign: "left", borderRadius: "md", variant: "outline", fontWeight: "normal", size: "sm", _focus: { shadow: "0px", background: "none" }, _hover: { background: "none" }, _active: { background: "none" }, rightIcon: _jsx(Box, Object.assign({ bg: "white", padding: "4px", pr: "0" }, { children: _jsx(ChevronDown, {}) })) }, { children: ((_c = props.value) === null || _c === void 0 ? void 0 : _c.target) || "Select options" })), _jsxs(MenuList, Object.assign({ maxW: "200px" }, { children: [_jsx(Box, Object.assign({ px: "8px", pb: "8px" }, { children: _jsx(Input, { placeholder: "Search", onChange: handleSearchInput, value: search }) })), optionsMap.map((opt) => {
                                                            var _a, _b, _c;
                                                            return (_jsx(MenuItem, Object.assign({ display: !opt.value.includes(search) && "none", onClick: () => {
                                                                    props.onChange(Object.assign(Object.assign({}, props.value), { target: opt.value || "" }));
                                                                } }, { children: _jsxs(Flex, { children: [_jsx(Text, Object.assign({ flex: 1, color: ((_a = props.value) === null || _a === void 0 ? void 0 : _a.target) === opt.value && "#0065FF" }, { children: opt.label })), ((_b = props.value) === null || _b === void 0 ? void 0 : _b.target) === opt.value && (_jsx(ChevronCheck, { color: ((_c = props.value) === null || _c === void 0 ? void 0 : _c.target) === opt.value && "#0065FF" }))] }) }), opt.value));
                                                        })] }))] })) }), _jsx(Box, Object.assign({ pt: "1rem" }, { children: params.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, Object.assign({ fontWeight: "semibold", fontSize: "sm", color: "#A6B0C1" }, { children: "Parameters" })), params.map((param) => {
                                                    var _a;
                                                    return (_jsxs(Grid, Object.assign({ templateColumns: "repeat(12, 1fr)", gap: 2, my: "8px" }, { children: [_jsx(GridItem, Object.assign({ colSpan: 3, display: "flex", alignItems: "center" }, { children: _jsx(Text, Object.assign({ fontSize: "sm", color: "#6F809A" }, { children: param.slug })) })), _jsx(GridItem, Object.assign({ colSpan: 9, my: "8px" }, { children: _jsx(props.PropertyEditor.string, { propDef: {
                                                                        type: "string",
                                                                        options: { format: "text" },
                                                                    }, propName: param.slug, value: (_a = props.value) === null || _a === void 0 ? void 0 : _a.params[param.slug], onChange: (value) => {
                                                                        handleUpdateParams(param.slug, value);
                                                                    } }) }))] }), param.slug));
                                                })] })) }))] }) }))] })));
            },
        };
    }),
    Component: (props) => {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        const boxWidth = React.useRef(null);
        const placeholder = props.hooks.useEvaluate(props.properties.placeholder);
        const defaultValue = props.hooks.useEvaluate(props.properties.defaultValue);
        const title = props.hooks.useEvaluate(props.properties.label);
        const params = useEvaluateObject(((_a = props.properties.options) === null || _a === void 0 ? void 0 : _a.params) || {});
        const ref = React.useRef(null);
        const data = props.hooks.useRuntimeInput(props.properties.data, props.data.page.row, {
            validate: (value) => {
                if (typeof value === "undefined") {
                    return { error: "" };
                }
                else if (!value) {
                    return { error: "Required field, Please enter the data" };
                }
            },
        });
        const [search, setSearch] = React.useState("");
        const { values } = useVariablesContext();
        React.useEffect(() => {
            const value = parseInt(defaultValue);
            data.onChange(isNaN(value) ? undefined : value);
        }, [defaultValue, data.onChange]);
        const tableName = React.useMemo(() => {
            var _a, _b;
            return ((_a = props.app.schema.tables.find((t) => t.name === props.pageSource.target)) === null || _a === void 0 ? void 0 : _a.name) ||
                ((_b = props.app.schema.views.find((v) => v.name === props.pageSource.target)) === null || _b === void 0 ? void 0 : _b.query.table);
        }, [props.app.schema, props.pageSource.target]);
        const relationData = React.useMemo(() => {
            const currentView = props.app.schema.tables.find((table) => table.name === tableName);
            const field = currentView === null || currentView === void 0 ? void 0 : currentView.columns.find((field) => field.name === props.properties.data.inputID);
            const table = field &&
                props.app.schema.tables.find((table) => table.name === field.references.targetTable);
            return { table, field };
        }, [props.app.schema, props.properties.data.inputID, tableName]);
        const isOneToMany = React.useMemo(() => {
            var _a, _b;
            return ((_a = relationData.field) === null || _a === void 0 ? void 0 : _a.references.type) === "OneToMany" &&
                !((_b = relationData.field) === null || _b === void 0 ? void 0 : _b.references.origin);
        }, [relationData]);
        const isManyToMany = React.useMemo(() => { var _a; return ((_a = relationData.field) === null || _a === void 0 ? void 0 : _a.references.type) === "ManyToMany"; }, [relationData]);
        const [selectedIds, setSelectedIds] = React.useState([]);
        const client = props.hooks.useClient();
        const fieldName = React.useMemo(() => {
            var _a, _b;
            if (isOneToMany) {
                const lastIndex = props.properties.data.inputID.lastIndexOf("_items");
                return props.properties.data.inputID.slice(0, lastIndex === -1 ? Infinity : lastIndex);
            }
            const lastIndex = props.properties.data.inputID.lastIndexOf((_a = relationData.field) === null || _a === void 0 ? void 0 : _a.references.targetTable);
            return props.properties.data.inputID
                .slice(0, lastIndex)
                .concat(tableName, props.properties.data.inputID.slice(lastIndex + (((_b = relationData.field) === null || _b === void 0 ? void 0 : _b.references.targetTable.length) || 0)));
        }, [
            props.properties.data.inputID,
            (_b = relationData.field) === null || _b === void 0 ? void 0 : _b.references.targetTable,
            tableName,
        ]);
        const options = useSWR([client, (_c = relationData.table) === null || _c === void 0 ? void 0 : _c.name, props.properties.options, params], () => __awaiter(void 0, void 0, void 0, function* () {
            var _m, _o, _p, _q, _r, _s, _t;
            const table = ((_m = relationData.table) === null || _m === void 0 ? void 0 : _m.name) === ((_o = props.properties.options) === null || _o === void 0 ? void 0 : _o.target)
                ? client.table((_p = relationData.table) === null || _p === void 0 ? void 0 : _p.name)
                : client.view((_q = props.properties.options) === null || _q === void 0 ? void 0 : _q.target);
            const data = yield table
                .readRows({ params }, {
                skip: !((_r = props.properties.options) === null || _r === void 0 ? void 0 : _r.target) || !((_s = relationData.table) === null || _s === void 0 ? void 0 : _s.name),
            })
                .toPromise();
            return ((_t = data.data) === null || _t === void 0 ? void 0 : _t.nodes) || [];
        }), {
            suspense: !!props.pageSource.prefetch,
        });
        const selectedData = useSWR([
            client,
            isManyToMany,
            isOneToMany,
            relationData.field,
            fieldName,
            (_e = (_d = props.data.page) === null || _d === void 0 ? void 0 : _d.row) === null || _e === void 0 ? void 0 : _e.id,
        ], () => {
            var _a, _b, _c, _d, _e;
            return isManyToMany || isOneToMany
                ? client
                    .table((_a = relationData.field) === null || _a === void 0 ? void 0 : _a.references.targetTable)
                    .readRows({
                    condition: {
                        [fieldName]: {
                            id: { $eq: (_c = (_b = props.data.page) === null || _b === void 0 ? void 0 : _b.row) === null || _c === void 0 ? void 0 : _c.id },
                        },
                    },
                }, {
                    skip: !((_e = (_d = props.data.page) === null || _d === void 0 ? void 0 : _d.row) === null || _e === void 0 ? void 0 : _e.id),
                })
                    .toPromise()
                    .then((data) => {
                    var _a;
                    return ((_a = data.data) === null || _a === void 0 ? void 0 : _a.nodes) || [];
                })
                : Promise.resolve([]);
        }, {
            suspense: !!props.pageSource.prefetch,
        });
        React.useEffect(() => {
            var _a;
            if (isManyToMany || isOneToMany) {
                setSelectedIds(((_a = selectedData.data) === null || _a === void 0 ? void 0 : _a.map((data) => data.id)) || []);
                return;
            }
            if (props.data.page.row[props.properties.data.inputID]) {
                data.onChange(props.data.page.row[props.properties.data.inputID]);
            }
        }, [
            (_f = props.data.page.row) === null || _f === void 0 ? void 0 : _f.id,
            selectedData.data,
            isManyToMany,
            isOneToMany,
            props.properties.data.inputID,
        ]);
        useFormSubmitHook((row) => __awaiter(void 0, void 0, void 0, function* () {
            if (!(isManyToMany || isOneToMany))
                return;
            const addRelations = selectedIds
                .filter((id) => !(selectedData.data || []).find((row) => row.id === id))
                .map((id) => ({
                operation: "AddRelation",
                instruction: {
                    table: tableName,
                    name: `addRelation_${tableName}_${props.properties.data.inputID}_${id}`,
                    relation: {
                        name: props.properties.data.inputID,
                        data: {
                            origin: row.id,
                            target: id,
                        },
                    },
                },
            }));
            const removeRelations = (selectedData.data || [])
                .map((row) => row.id)
                .filter((id) => !selectedIds.includes(id))
                .map((id) => ({
                operation: "RemoveRelation",
                instruction: {
                    table: tableName,
                    name: `removeRelation_${tableName}_${props.properties.data.inputID}_${id}`,
                    relation: {
                        name: props.properties.data.inputID,
                        data: {
                            origin: row.id,
                            target: id,
                        },
                    },
                },
            }));
            yield client.project.axios({
                baseURL: client.project.config.endpoint,
                url: "/v1/execute",
                method: "POST",
                data: {
                    operations: addRelations.concat(removeRelations),
                },
            });
        }), [
            isManyToMany,
            selectedIds,
            selectedData.data,
            tableName,
            props.properties.data.inputID,
            client,
        ]);
        const itemRow = (_g = options.data) === null || _g === void 0 ? void 0 : _g.find((row) => row.id === data.value);
        return (_jsxs(Box, Object.assign({ display: props.properties.hidden ? "none" : undefined }, { children: [_jsx(InputComponentLabel, { title: title, name: "dropdown-relation", isRequired: (_h = props.properties.data.validation) === null || _h === void 0 ? void 0 : _h.required, isEmpty: title.length === 0 }), _jsx(Box, Object.assign({ ref: ref }, { children: _jsx(Portal, Object.assign({ containerRef: ref }, { children: _jsxs(Menu, Object.assign({ isLazy: true }, { children: [_jsx(props.components.ListItemVariables, Object.assign({ variables: itemRow || {} }, { children: _jsx(MenuButtonValue, Object.assign({ ref: boxWidth }, props, { children: isManyToMany || isOneToMany
                                            ? (options.data || [])
                                                .filter((row) => selectedIds.includes(row.id))
                                                .map((row) => {
                                                return format(props.properties.itemLabel, Object.assign(Object.assign({}, values), Object.fromEntries(Object.entries(row).map(([key, value]) => [
                                                    `item.${key}`,
                                                    value,
                                                ]))));
                                            })
                                                .join(", ")
                                            : null })) })), _jsx(Portal, Object.assign({ appendToParentPortal: true }, { children: _jsxs(MenuList, Object.assign({ border: "0px", width: (_j = boxWidth === null || boxWidth === void 0 ? void 0 : boxWidth.current) === null || _j === void 0 ? void 0 : _j.offsetWidth, zIndex: 3 }, { children: [_jsx(Text, Object.assign({ color: "gray", py: 2, px: 4, style: { cursor: "default" } }, { children: placeholder })), ((_k = options.data) === null || _k === void 0 ? void 0 : _k.length) > MAX_DISPLAY_OPTION && (_jsx(Input, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Search...", mb: 2 })), _jsx(Box, Object.assign({ maxH: MAX_DISPLAY_OPTION * 8, overflowY: "auto" }, { children: (_l = options.data) === null || _l === void 0 ? void 0 : _l.map((option) => (_jsx(props.components.ListItemVariables, Object.assign({ variables: option }, { children: isManyToMany || isOneToMany ? (_jsx(ManyToManyOption, Object.assign({ item: option, onChange: setSelectedIds, value: selectedIds, search: search }, props))) : (_jsx(Option, Object.assign({ item: option, onChange: data.onChange, value: data.value, search: search }, props))) }), option.id))) }))] })) }))] })) })) })), !!data.validation.error && (_jsx(Text, Object.assign({ fontSize: "sm", color: "red" }, { children: data.validation.error })))] })));
    },
});
export default DropdownRelation;
//# sourceMappingURL=dropdownRelation.js.map