import { __awaiter, __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
import { Box, Button, Flex } from "@chakra-ui/react";
import _ from "lodash";
import { Scrollbars } from "rc-scrollbars";
import React from "react";
import { v4 as uuidv4 } from "uuid";
import { Scene, useComposer } from "./Composer";
import GroupComponentsContext from "./GroupComponentsContext";
import { useNavigations } from "./hooks/navigations";
import qore from "./hooks/qore";
import { useSourceHooks } from "./hooks/sourceHooks/useSourceHooks";
import { useActionTrigger } from "./hooks/useActionTrigger";
import { FormSubmitHookContext } from "./hooks/FormSubmitHook";
import { useRefreshDataContext } from "./hooks/useRefreshData";
import aixp from "./integrations/aixp";
import gtm from "./integrations/gtm";
import { useSource } from "./hooks/useSource";
import NavigationLayout from "./NavigationLayout";
import { PageHeadingsMap } from "./NavigationLayout/sidebar-layout/heading-maps";
import { useQRScannerAction } from "./QRScanner.action";
import { getThemes } from "./registeredThemes";
import RuntimeComponent from "./RuntimeComponent";
import { RuntimeContext } from "./RuntimeContext";
import { inputFieldPrefix, RuntimeInputContext } from "./RuntimeInput";
import { boxed } from "./utils/boxed";
import { omit } from "./utils/omit";
import { VariablesProvider } from "./VariablesContext";
const PageFootersMap = {
    display: () => null,
    form: (props) => {
        const invalidValues = RuntimeInputContext.useSelectState((state) => state.invalidValues);
        const isSubmittable = React.useMemo(() => !Object.keys(invalidValues).length, [invalidValues]);
        const [loading, setLoading] = React.useState(false);
        const onSubmit = React.useCallback(() => {
            if (!isSubmittable)
                return;
            setLoading(true);
            props.onSubmit().finally(() => setLoading(false));
        }, [props.onSubmit, isSubmittable]);
        return (_jsx(Flex, Object.assign({ py: "16px", px: 4 }, { children: _jsx(Button, Object.assign({ variant: "solid", colorScheme: "blue", width: { base: "100%", md: "260px" }, ml: { base: "none", md: "auto" }, mr: { base: "none", md: "15px" }, disabled: loading || !isSubmittable, onClick: onSubmit }, { children: "Save" })) })));
    },
};
const useTableOrView = (id) => {
    const tables = RuntimeContext.useSelectState((state) => state.schema.tables);
    const views = RuntimeContext.useSelectState((state) => state.schema.views);
    return React.useMemo(() => tables.find((t) => t.name === id) || views.find((v) => v.name === id), [views, id]);
};
export const fakeRow = { id: "" };
export default function ActivePage(props) {
    const { page } = props;
    const source = useSource();
    return page ? _jsx(Page, { page: props.page, source: source }) : null;
}
export function Page({ page, source, excludeNavigation, }) {
    var _a;
    const groupCompActions = GroupComponentsContext.useActions();
    const sourceHooks = useSourceHooks(source);
    const { code } = useQRScannerAction();
    const app = RuntimeContext.useSelectState((state) => state);
    const { data, error, revalidate, status } = sourceHooks.useFetch();
    const runtimeInputActions = RuntimeInputContext.useActions();
    const { refreshData } = useRefreshDataContext();
    const firstRow = data || fakeRow;
    const onOpenAction = useActionTrigger(page === null || page === void 0 ? void 0 : page.properties.values.onOpen, firstRow, source);
    React.useEffect(() => {
        const timeout = setTimeout(() => {
            onOpenAction.handleClick();
        }, 1000);
        return () => {
            clearTimeout(timeout);
            runtimeInputActions.resetValidation();
            runtimeInputActions.resetValues();
        };
    }, [page.id]);
    const navigationLayout = RuntimeContext.useSelectState((state) => state.navbar.sidetop.position);
    const inputValues = RuntimeInputContext.useSelectState((state) => state.values);
    const mergedRow = React.useMemo(() => {
        return Object.assign(Object.assign({}, code), firstRow);
    }, [firstRow, code]);
    const Footer = PageFootersMap[(page === null || page === void 0 ? void 0 : page.mode) || "display"];
    const components = RuntimeContext.useSelectState((state) => state.maps.component);
    const pageComponentsMap = React.useMemo(() => page.components
        .map(({ component }) => components[component])
        .filter(Boolean), [page.components, components]);
    const onScrollToBottomAction = useActionTrigger(page.properties.values.onScrollToBottom, firstRow, source);
    const hasReachedBottomRef = React.useRef(false);
    const handleScrollEnd = React.useCallback(() => {
        if (hasReachedBottomRef.current)
            return;
        onScrollToBottomAction.handleClick();
    }, [onScrollToBottomAction]);
    const pageComponentsGroup = React.useMemo(() => {
        const layer1 = {};
        pageComponentsMap.forEach((comp) => {
            if (comp && !!comp.metadata && !!comp.metadata.layout) {
                if (!layer1[comp.metadata.layout.id]) {
                    layer1[comp.metadata.layout.id] = {};
                }
                if (!layer1[comp.metadata.layout.id][comp.metadata.layout.column]) {
                    layer1[comp.metadata.layout.id][comp.metadata.layout.column] = [];
                }
                layer1[comp.metadata.layout.id][comp.metadata.layout.column].push({
                    component: comp.id,
                });
            }
        });
        groupCompActions.setComponentsByLayout(layer1);
        const parentComponent = page.components
            .filter((component) => {
            const comp = components[component.component];
            return (comp &&
                (!comp.metadata ||
                    (!comp.metadata.layout && !comp.metadata.container)));
        })
            .map((comp) => components[comp.component]);
        return _.sortBy(parentComponent, "metadata.idx").map((comp) => ({
            component: comp.id,
        }));
    }, [page.components, components]);
    const childrenMap = React.useMemo(() => _.groupBy(pageComponentsMap, "metadata.container"), [pageComponentsMap]);
    const projectID = RuntimeContext.useSelectState((state) => state.config.projectID);
    const tableOrView = useTableOrView(source.target || "");
    const composer = useComposer();
    const aixpIntegration = aixp.useIntegration();
    gtm.useIntegration();
    const client = qore.useClient();
    const onSuccessAction = useActionTrigger(page.properties.values.onSuccess, mergedRow, source);
    const formSubmitHook = React.useContext(FormSubmitHookContext);
    const handleSubmit = React.useCallback(() => __awaiter(this, void 0, void 0, function* () {
        var _b, _c, _d, _e;
        const rowInputValues = {};
        const files = {};
        for (const param of sourceHooks.inputParams) {
            const fieldInputKey = inputFieldPrefix + param.slug;
            if (inputValues[fieldInputKey] instanceof File ||
                ((_c = (_b = inputValues[fieldInputKey]) === null || _b === void 0 ? void 0 : _b.constructor) === null || _c === void 0 ? void 0 : _c.name) === "File") {
                files[param.slug] = inputValues[fieldInputKey];
                continue;
            }
            if (typeof inputValues[fieldInputKey] !== "undefined") {
                const tableOrViewColumn = tableOrView &&
                    tableOrView.columns.find((column) => column.name === param.slug);
                if (!!mergedRow.id &&
                    ((_d = tableOrViewColumn === null || tableOrViewColumn === void 0 ? void 0 : tableOrViewColumn.references) === null || _d === void 0 ? void 0 : _d.type) === "OneToMany" &&
                    ((_e = tableOrViewColumn === null || tableOrViewColumn === void 0 ? void 0 : tableOrViewColumn.references) === null || _e === void 0 ? void 0 : _e.origin)) {
                    rowInputValues[param.slug] = inputValues[fieldInputKey];
                    continue;
                }
                rowInputValues[param.slug] = inputValues[fieldInputKey];
            }
        }
        // eslint-disable-next-line fp/no-let -- TODO: refactor this
        let newRow = data || {};
        if (page.id === "register") {
            if (!rowInputValues.role) {
                delete rowInputValues.role;
            }
            const duplicateInput = omit(["password"], _.cloneDeep(rowInputValues));
            aixpIntegration.run((integration) => {
                integration.identify({
                    userId: duplicateInput["external_id"],
                    anonymousId: uuidv4(),
                    traits: duplicateInput,
                });
                integration.track({
                    userId: duplicateInput["external_id"],
                    anonymousId: uuidv4(),
                    event: "register",
                    properties: duplicateInput,
                    context: {
                        traits: duplicateInput,
                    },
                });
            });
        }
        if (!mergedRow.id) {
            newRow = yield sourceHooks.store(rowInputValues);
            if (tableOrView) {
                yield Promise.all(Object.entries(files).map(([column, file]) => client
                    .table("query" in tableOrView
                    ? tableOrView.query.table
                    : tableOrView.name)
                    .upload(newRow.id, column, file)));
            }
        }
        else if (Object.keys(rowInputValues).length > 0) {
            newRow = yield sourceHooks.store(Object.assign(Object.assign({}, rowInputValues), { id: mergedRow.id }));
        }
        yield formSubmitHook.triggerSubmitHooks(newRow);
        yield revalidate({
            networkPolicy: "network-only",
        });
        yield onSuccessAction.handleClickWithAdditionValues(newRow);
        refreshData();
        const onSuccessActions = boxed(page.properties.values.onSuccess).filter((action) => action.type !== "none");
        if (onSuccessActions.length === 0 ||
            onSuccessActions.find((action) => action.type !== "jump_to_page" &&
                action.type !== "back_to_login" &&
                action.type !== "trigger_action" &&
                action.type !== "close_page_modal")) {
            yield composer.back();
        }
    }), [
        refreshData,
        sourceHooks,
        mergedRow.id,
        tableOrView,
        inputValues,
        composer.back,
        projectID,
        formSubmitHook,
    ]);
    React.useEffect(() => {
        groupCompActions.setMetadata({
            row: mergedRow,
            source: source,
            error: error,
            loading: status === "loading",
            revalidate,
        });
    }, [mergedRow, source, error, status]);
    const theme = (_a = getThemes().find((theme) => theme.id === app.theme.id)) === null || _a === void 0 ? void 0 : _a.theme;
    const navigations = useNavigations();
    const Heading = PageHeadingsMap[(page === null || page === void 0 ? void 0 : page.mode) || "display"];
    const handleDeleteRow = React.useCallback(() => __awaiter(this, void 0, void 0, function* () {
        yield sourceHooks.del({ id: mergedRow.id });
        composer.back();
    }), [mergedRow.id, sourceHooks]);
    const renderThumb = React.useCallback((_a) => {
        var { style } = _a, props = __rest(_a, ["style"]);
        return (_jsx("div", Object.assign({ style: Object.assign(Object.assign({}, style), { backgroundColor: theme.colors.text["900"] }) }, props)));
    }, [theme]);
    const showHeading = React.useMemo(() => page.properties.values.headerStyle === "none" ||
        navigationLayout === "topbar" ||
        excludeNavigation, [page.properties.values.headerStyle, navigationLayout]);
    return (_jsx(VariablesProvider, Object.assign({ values: mergedRow }, { children: _jsx(NavigationLayoutContainer, Object.assign({ page: page, layout: navigationLayout, excludeNavigation: excludeNavigation }, { children: _jsx(Scene, { children: _jsxs(Box, Object.assign({ w: "full", h: "full", bg: "bg.900", overflowY: "hidden" }, { children: [_jsx(Box, Object.assign({ display: showHeading ? "none" : "initial", position: "sticky", top: "0", right: "0", bg: "bg.900", zIndex: 1, color: "text.900" }, { children: _jsx(Heading, { onAbort: composer.back, navigations: navigations, onDeleteRow: handleDeleteRow, page: page, row: mergedRow }) })), _jsx(Box, Object.assign({ height: showHeading ? "100%" : "calc(100% - 57px)", width: "full" }, { children: _jsxs(Scrollbars, Object.assign({ universal: true, renderThumbHorizontal: renderThumb, renderThumbVertical: renderThumb, onScrollStop: handleScrollEnd, style: { zIndex: 0 }, autoHide: true }, { children: [pageComponentsGroup.map((component) => {
                                        if (!components[component.component]) {
                                            return null;
                                        }
                                        return (_jsx(RuntimeComponent, { row: mergedRow, source: source, error: error, loading: status === "loading", revalidate: revalidate, component: component, childrenMap: childrenMap }, component.component));
                                    }), _jsx(Footer, { page: page, row: mergedRow, onSubmit: handleSubmit })] })) }))] })) }) })) })));
}
const NavigationLayoutContainer = ({ page, layout, excludeNavigation, children }) => {
    if (excludeNavigation)
        return _jsx(_Fragment, { children: children });
    return (_jsx(NavigationLayout, Object.assign({ page: page, layout: layout }, { children: children })));
};
//# sourceMappingURL=ActivePage.js.map