import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
import { ChevronDownIcon } from "@chakra-ui/icons";
import { Box, Button, Center, Divider, Icon, Menu, MenuButton, MenuItemOption, MenuList, MenuOptionGroup, Stack, Text, } from "@chakra-ui/react";
import { Plus } from "@feedloop/icon";
import EditorContext from "@qorebase/app-runtime/src/EditorContext";
import { generateFieldName } from "@qorebase/app-runtime/src/hooks/sourceHooks/openAPISourceHooks";
import { useSourceHooks } from "@qorebase/app-runtime/src/hooks/sourceHooks/useSourceHooks";
import { getComponent, isComponent, } from "@qorebase/app-runtime/src/interfaces";
import { useQRActionsVariables } from "@qorebase/app-runtime/src/QRScanner.action";
import { RuntimeContext } from "@qorebase/app-runtime/src/RuntimeContext";
import { useInputVariables } from "@qorebase/app-runtime/src/RuntimeInput";
import { useSchemaSource } from "@qorebase/app-runtime/src/hooks/useSchemaSource";
import { groupBy } from "@qorebase/app-runtime/src/utils/groupBy";
import { VariablesProvider } from "@qorebase/app-runtime/src/VariablesContext";
import React from "react";
import { useHidden } from "../hooks/useHidden";
import { ColumnSetting, ComponentPropertyEditor, ListSourceSelector, NestedListSourceSelector, RecordListSourceSelector, RecordSourceSelector, ShowAndDisableConditionEditor, } from "./ComponentPropertyEditor";
import PropsGroup from "./PropsGroup";
import variablesFieldTypes from "./variablesFieldTypes";
import { usePageParam } from "@qorebase/app-runtime/src/hooks/usePageParam";
function sectionBy(array, keySelector, sections) {
    return array.reduce((obj, item) => {
        var _a;
        const key = keySelector(item);
        const section = sections && sections[key] ? sections[key] : {};
        return Object.assign(Object.assign({}, obj), { [key]: Object.assign(Object.assign({}, section), { propsDefs: (((_a = obj[key]) === null || _a === void 0 ? void 0 : _a.propsDefs) || []).concat([item]) }) });
    }, {});
}
function groupBySection(items, sections) {
    const uncategorized = "uncategorized";
    const newItems = new Map();
    items.forEach((value, name) => {
        const sectioned = sectionBy(value, ([, def]) => def.section || uncategorized, sections);
        newItems.set(name, sectioned);
    });
    return newItems;
}
function SectionGroup(props) {
    const { isHidden } = useHidden(props.hideOrShownOn, props.values);
    if (props.sectionId === "uncategorized")
        return _jsx(_Fragment, { children: props.children });
    else if (isHidden)
        return null;
    return (_jsxs(_Fragment, { children: [props.title && (_jsx(Text, Object.assign({ mb: "8px", color: "grey" }, { children: props.title }))), _jsx(Box, Object.assign({ background: props.background || "#F5F5F5", padding: "8px", borderRadius: "sm" }, { children: props.children }))] }));
}
const ShowAndDisableWhen = (props) => {
    var _a, _b, _c;
    const runtimeActions = RuntimeContext.useActions();
    return (_jsxs(Stack, Object.assign({ p: 4 }, { children: [_jsx(Box, { children: _jsxs(Text, Object.assign({ fontWeight: "semibold" }, { children: [props.name, " when"] })) }), ((_b = (_a = props.compInstance) === null || _a === void 0 ? void 0 : _a[props.condition]) === null || _b === void 0 ? void 0 : _b.conditions.length) > 0 && (_jsxs(Box, Object.assign({ display: "flex", alignItems: "center" }, { children: [_jsxs(Menu, { children: [_jsx(MenuButton, Object.assign({ as: Button, mr: 2, rightIcon: _jsx(ChevronDownIcon, {}), size: "sm", textTransform: "capitalize" }, { children: props.compInstance[props.condition].type })), _jsx(MenuList, Object.assign({ zIndex: 3 }, { children: _jsxs(MenuOptionGroup, Object.assign({ type: "radio", defaultValue: props.compInstance[props.condition].type, onChange: (type) => runtimeActions[props.name === "Show"
                                        ? "updateComponentShowCondition"
                                        : "updateComponentDisableCondition"]({ component: props.compInstance.id }, (draft) => {
                                        draft.type = type;
                                    }) }, { children: [_jsx(MenuItemOption, Object.assign({ value: "all" }, { children: "All" })), _jsx(MenuItemOption, Object.assign({ value: "any" }, { children: "Any" }))] })) }))] }), "of the following are true :"] }))), !!props.compInstance &&
                (Array.isArray(props.compInstance[props.condition])
                    ? props.compInstance[props.condition].length
                    : (_c = props.compInstance[props.condition]) === null || _c === void 0 ? void 0 : _c.conditions.length) ? (props.name === "Show" ? (_jsx(ShowAndDisableConditionEditor, { instance: props.compInstance, condition: "showCondition" })) : (_jsx(ShowAndDisableConditionEditor, { instance: props.compInstance, condition: "disableCondition" }))) : (_jsx(Box, Object.assign({ py: 2 }, { children: _jsx(Text, Object.assign({ padding: 4, color: "gray.600", borderRadius: "md", backgroundColor: "#EDF2F7" }, { children: "No condition added. Click button below to add your first condition" })) }))), _jsx(Box, { children: _jsxs(Button, Object.assign({ size: "sm", variant: "outline", onClick: () => {
                        runtimeActions[props.name === "Show"
                            ? "addComponentShowCondition"
                            : "addComponentDisableCondition"]({
                            component: props.compInstance.id,
                        });
                    } }, { children: [_jsx(Icon, { as: Plus, mr: 2 }), "Add condition"] })) })] })));
};
export const usePageVariables = () => {
    const pageParam = usePageParam();
    const currentPage = RuntimeContext.useSelectState((state) => state.maps.page[pageParam]);
    const inputVariables = useInputVariables();
    const qrActionsSuggestions = useQRActionsVariables();
    const sourceHooks = useSourceHooks({
        type: "record",
        target: currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceID,
        rowId: "",
        params: {},
        defaultRow: { type: "first-row" },
    });
    const paramsVariables = React.useMemo(() => (currentPage === null || currentPage === void 0 ? void 0 : currentPage.params)
        ? Object.keys(currentPage.params).map((key) => ({
            id: `params.${key}`,
            display: `params.${key}`,
        }))
        : [{ id: "params.rowId", display: "params.rowId" }], [currentPage === null || currentPage === void 0 ? void 0 : currentPage.params]);
    const rowVariables = React.useMemo(() => (currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceType) === "custom"
        ? sourceHooks.fields
        : sourceHooks.fields.concat({
            id: "id",
            display: "id",
        }), [currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceType, sourceHooks.fields]);
    const variables = React.useMemo(() => [
        ...qrActionsSuggestions,
        ...inputVariables,
        ...paramsVariables,
        ...rowVariables,
    ], [qrActionsSuggestions, inputVariables, paramsVariables, rowVariables]);
    return { variables };
};
const emptyObj = {};
export const ComponentEditor = (props) => {
    var _a;
    const { compInstance, compDefinition } = props;
    const runtimeActions = RuntimeContext.useActions();
    const pageParam = usePageParam();
    const currentPage = RuntimeContext.useSelectState((state) => state.maps.page[pageParam]);
    const components = RuntimeContext.useSelectState((state) => state.maps.component);
    const parentCompInstance = RuntimeContext.useSelectState((state) => {
        var _a;
        const container = state.maps.component[compInstance.metadata.container];
        return container &&
            container.metadata.container &&
            !((_a = container === null || container === void 0 ? void 0 : container.source) === null || _a === void 0 ? void 0 : _a.target)
            ? state.maps.component[container.metadata.container]
            : container;
    });
    const findParent = React.useCallback((instance) => {
        var _a;
        const container = components[instance.metadata.container];
        return container &&
            container.metadata.container &&
            !((_a = container === null || container === void 0 ? void 0 : container.source) === null || _a === void 0 ? void 0 : _a.target)
            ? components[container.metadata.container]
            : container;
    }, [components]);
    const parentInstances = React.useMemo(function parentInstances(instance = compInstance) {
        const parent = findParent(instance);
        return parent ? [parent, ...parentInstances(parent)] : [];
    }, [compInstance, findParent]);
    const app = RuntimeContext.useSelectState((state) => state);
    const LayoutType = React.useMemo(() => {
        if (!compInstance.metadata || !compInstance.metadata.layout)
            return;
        return isComponent(components[compInstance.metadata.layout.id], "ColumnLayout3")
            ? "col-3"
            : "col-2";
    }, [(_a = compInstance === null || compInstance === void 0 ? void 0 : compInstance.metadata) === null || _a === void 0 ? void 0 : _a.layout, components]);
    const propsDef = React.useMemo(() => {
        return Object.entries(compDefinition.propDefinition);
    }, [compDefinition.propDefinition, app]);
    const schema = RuntimeContext.useSelectState((state) => state.schema);
    const tablesAndViews = useSchemaSource([
        "tables",
        "views",
        "insights",
        "queries",
    ]);
    const customSources = RuntimeContext.useSelectState((state) => state.customSources);
    const pageView = React.useMemo(() => tablesAndViews.find((view) => {
        var _a, _b;
        return ((_a = compInstance === null || compInstance === void 0 ? void 0 : compInstance.source) === null || _a === void 0 ? void 0 : _a.type) === "record" ||
            ((_b = compInstance === null || compInstance === void 0 ? void 0 : compInstance.source) === null || _b === void 0 ? void 0 : _b.type) === "standalone-list"
            ? view.name === (compInstance.source.target || (currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceID))
            : view.name === (currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceID);
    }), [currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceID, compInstance === null || compInstance === void 0 ? void 0 : compInstance.source]);
    const currentView = React.useMemo(() => {
        var _a, _b, _c;
        const instance = compInstance;
        const sourceId = ((_a = instance.source) === null || _a === void 0 ? void 0 : _a.target) || (currentPage === null || currentPage === void 0 ? void 0 : currentPage.sourceID);
        const view = tablesAndViews.find((view) => view.name === sourceId);
        if (!view) {
            return customSources[sourceId];
        }
        if (((_b = instance.source) === null || _b === void 0 ? void 0 : _b.type) !== "nested-list") {
            return view;
        }
        const fieldId = instance.source.fieldId;
        const field = view.columns.find((field) => field.name === fieldId);
        const linkedViewName = ("references" in field && ((_c = field.references) === null || _c === void 0 ? void 0 : _c.targetTable)) || "";
        return tablesAndViews.find((view) => view.name === linkedViewName);
    }, [compDefinition.type, tablesAndViews, compInstance, currentPage]);
    const parentView = React.useMemo(() => {
        var _a;
        const instance = parentCompInstance;
        const sourceId = (_a = instance === null || instance === void 0 ? void 0 : instance.source) === null || _a === void 0 ? void 0 : _a.target;
        return tablesAndViews.find((view) => view.name === sourceId);
    }, [parentCompInstance, tablesAndViews]);
    const parentViews = React.useMemo(() => {
        return parentInstances
            .map((instance) => {
            var _a;
            const sourceId = (_a = instance === null || instance === void 0 ? void 0 : instance.source) === null || _a === void 0 ? void 0 : _a.target;
            return tablesAndViews.find((view) => view.name === sourceId);
        })
            .filter(Boolean);
    }, [parentCompInstance, tablesAndViews]);
    const isView = React.useMemo(() => Boolean(schema.views.find((view) => view.name === (currentView === null || currentView === void 0 ? void 0 : currentView.name))), [currentView]);
    const isQuery = React.useMemo(() => Boolean(schema.queries.find((query) => query.name === (currentView === null || currentView === void 0 ? void 0 : currentView.name))), [currentView]);
    const itemsVariables = React.useMemo(() => {
        const items = [
            {
                id: "rowId",
                display: "rowId",
            },
            {
                id: "modalRowId",
                display: "modalRowId",
            },
        ];
        if (compDefinition.type === "none" && parentViews.length === 0) {
            return items;
        }
        try {
            if (currentView && "schemaUrl" in currentView) {
                return generateFieldName(currentView.columns.type === "list"
                    ? currentView.columns.items
                    : currentView.columns, "item").map(([fieldName]) => ({
                    id: fieldName,
                    display: fieldName,
                }));
            }
        }
        catch (error) { }
        return [
            // @ts-ignore
            ...((currentView === null || currentView === void 0 ? void 0 : currentView.columns) || []),
            ...parentViews
                .slice()
                .reverse()
                .flatMap((view) => view.columns || []),
        ]
            .filter((field) => {
            var _a;
            return isQuery ||
                ((field.references || variablesFieldTypes.has(field.type)) &&
                    // @ts-ignore
                    (!isView || ((_a = currentView.query) === null || _a === void 0 ? void 0 : _a.fields.includes(field.name))));
        })
            .concat({
            type: "text",
            name: "id",
        })
            .map((field) => ({
            display: `item.${field.name}`,
            id: `item.${field.name}`,
        }))
            .concat(items);
    }, [compDefinition, isView, currentView === null || currentView === void 0 ? void 0 : currentView.columns, parentView === null || parentView === void 0 ? void 0 : parentView.columns]);
    const { variables: pageVariables } = usePageVariables();
    const groupedPropsDef = React.useMemo(() => {
        const groupped = groupBy(propsDef, ([, def]) => def.group || "uncategorized");
        const containerChildGroupped = [...groupped].filter(([k]) => k !== "Width" && k !== "Height");
        const grouppedBySection = groupBySection(new Map(compInstance.kind === "container" && compInstance.metadata.container
            ? groupped
            : containerChildGroupped), compDefinition.sections);
        return grouppedBySection;
    }, [propsDef, compDefinition.sections]);
    const uncategorized = React.useMemo(() => {
        return groupedPropsDef.get("uncategorized") || emptyObj;
    }, [groupedPropsDef]);
    return (_jsx(VariablesProvider, Object.assign({ variables: pageVariables }, { children: _jsxs(VariablesProvider, Object.assign({ variables: itemsVariables }, { children: [compDefinition.type === "list" ||
                    compDefinition.type === "standalone-list" ? (_jsx(ListSourceSelector, { instance: compInstance })) : compDefinition.type === "nested-list" ? (_jsx(NestedListSourceSelector, { instance: compInstance })) : compDefinition.type === "record" ? (_jsx(RecordSourceSelector, { instance: compInstance })) : compDefinition.type === "record-list" ? (_jsx(RecordListSourceSelector, { instance: compInstance })) : null, uncategorized && Object.keys(uncategorized).length > 0 ? (_jsx(Stack, Object.assign({ p: 4 }, { children: Object.keys(uncategorized).map((sectionKey) => {
                        const { title, propsDefs: sectionDefs, background, hideOrShownOn, } = uncategorized[sectionKey];
                        return (_jsx(Stack, Object.assign({ spacing: 2, pb: 4 }, { children: _jsx(SectionGroup, Object.assign({ sectionId: sectionKey, title: title, background: background, hideOrShownOn: hideOrShownOn, values: compInstance.properties || compDefinition.defaultProps }, { children: sectionDefs
                                    .filter(([, propsDef]) => !propsDef.hidden)
                                    .map(([propName, propDef]) => (_jsx(ComponentPropertyEditor, { propName: propName, value: typeof compInstance.properties[propName] ===
                                        "undefined"
                                        ? compDefinition.defaultProps[propName]
                                        : compInstance.properties[propName], view: pageView, propDef: propDef, handleChange: (value) => {
                                        runtimeActions.setComponentProperty({ component: compInstance.id }, propName, value);
                                    }, Editor: compDefinition.Editor, values: compInstance.properties ||
                                        compDefinition.defaultProps, instance: compInstance }, propName))) }), sectionKey) }), sectionKey));
                    }) }))) : null, groupedPropsDef
                    .entries()
                    .filter(([key]) => key !== "uncategorized")
                    .map(([groupName, propsDefs]) => {
                    return (_jsx(Box, Object.assign({ mt: "0px !important" }, { children: _jsx(PropsGroup, Object.assign({ name: groupName }, { children: Object.keys(propsDefs).map((sectionKey) => {
                                const { title, propsDefs: sectionDefs, background, hideOrShownOn, } = propsDefs[sectionKey];
                                return (_jsx(Stack, Object.assign({ spacing: 2, pb: 4 }, { children: _jsx(SectionGroup, Object.assign({ sectionId: sectionKey, title: title, background: background, hideOrShownOn: hideOrShownOn, values: compInstance.properties ||
                                            compDefinition.defaultProps }, { children: _jsx(Stack, Object.assign({ spacing: 2, pb: 4 }, { children: sectionDefs
                                                .filter(([, propsDef]) => !propsDef.hidden)
                                                .map(([propName, propDef]) => (_jsx(ComponentPropertyEditor, { propName: propName, value: typeof compInstance.properties[propName] ===
                                                    "undefined"
                                                    ? compDefinition.defaultProps[propName]
                                                    : compInstance.properties[propName], view: currentView, propDef: propDef, handleChange: (value) => {
                                                    runtimeActions.setComponentProperty({ component: compInstance.id }, propName, value);
                                                }, Editor: compDefinition.Editor, values: compInstance.properties ||
                                                    compDefinition.defaultProps, instance: compInstance }, propName))) })) }), sectionKey) }), sectionKey));
                            }) })) }), groupName));
                })
                    .toArray(), !!compInstance.metadata && !!compInstance.metadata.layout && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(ColumnSetting, { instance: compInstance, type: LayoutType })] })), _jsx(ShowAndDisableWhen, { name: "Show", condition: "showCondition", compInstance: compInstance }), compDefinition.group === "input" &&
                    compDefinition.icon !== "RichTextInput" &&
                    compDefinition.icon !== "Pencil" && (_jsx(ShowAndDisableWhen, { name: "Disable", condition: "disableCondition", compInstance: compInstance }))] })) })));
};
export default function ComponentEditorPanel() {
    const activeComponent = EditorContext.useSelectState((state) => state.activeComponent);
    const compInstance = RuntimeContext.useSelectState((state) => state.maps.component[activeComponent]);
    const compDefinition = React.useMemo(() => getComponent(compInstance === null || compInstance === void 0 ? void 0 : compInstance.componentID), [compInstance === null || compInstance === void 0 ? void 0 : compInstance.componentID]);
    if (!compInstance)
        return (_jsx(Center, Object.assign({ p: 4, pt: 6 }, { children: _jsx(Text, Object.assign({ color: "gray.500", textAlign: "center" }, { children: "No component selected" })) })));
    if (!compDefinition)
        return (_jsx(Center, Object.assign({ p: 4, pt: 6 }, { children: _jsx(Text, Object.assign({ color: "gray.500", textAlign: "center" }, { children: "Component definition not found" })) })));
    return (_jsx(Box, { children: _jsx(ComponentEditor, { compInstance: compInstance, compDefinition: compDefinition }, activeComponent) }));
}
//# sourceMappingURL=ComponentEditorPanel.js.map