import { __awaiter } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
import React from "react";
import { ChevronDown, Plus, ShareAlt, MoreHorizontal, Information, } from "@feedloop/icon";
import { Box, Button, Icon, SimpleGrid, Text, useClipboard, useDisclosure, Image, Tooltip, useToast, HStack, Spacer, IconButton, Menu, MenuButton, MenuItem, MenuList, Flex, Badge, CircularProgress, FormControl, Input, InputGroup, InputRightElement, useOutsideClick, } from "@chakra-ui/react";
import { useRouter } from "next/router";
import qoreStorageClient from "../hooks/qoreStorageClient";
import CreateApplicationModal from "./CreateApplicationModal";
import _ from "lodash";
import dayjs from "dayjs";
import subdomain from "../utils/subdomain";
import useUpdateWhitelist from "../hooks/useUpdateWhitelist";
import { v4 as uuidv4 } from "uuid";
import { css } from "@emotion/react";
import iconsList from "@qorebase/app-runtime/src/components/iconsList";
import DeleteApplicationModal from "./DeleteApplicationModal";
import relativeTime from "dayjs/plugin/relativeTime";
import EditorContext from "@qorebase/app-runtime/src/EditorContext";
import getConfig from "next/config";
const { publicRuntimeConfig } = getConfig();
dayjs.extend(relativeTime);
const AppDomainContent = (props) => {
    const { onCopy, hasCopied } = useClipboard(props.address);
    const toast = useToast();
    const handleOpenAddress = React.useCallback(() => {
        window.open(`https://${props.address}`, "_blank");
    }, [props.address]);
    React.useEffect(() => {
        if (hasCopied) {
            toast({
                title: "Successfull copying the link",
                status: "success",
                duration: 1000,
                isClosable: true,
            });
        }
    }, [hasCopied]);
    return (_jsxs(Box, Object.assign({ borderRadius: "4px", border: "1px solid #E7E7E7", bg: props.status === "deleted" ? "#E7E7E7" : "white", display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px" }, { children: [_jsx(Tooltip, Object.assign({ isDisabled: props.status === "deleted", label: "Open application in new tab", shouldWrapChildren: true, hasArrow: true }, { children: _jsx(Text, Object.assign({ fontSize: "12px", color: props.status === "deleted" ? "#A2A2A2" : "grey.base", onClick: () => {
                        props.status !== "deleted" && handleOpenAddress();
                    }, "data-test": "app-link" }, { children: props.address })) })), _jsx(Tooltip, Object.assign({ isDisabled: props.status === "deleted", label: "Copy link", shouldWrapChildren: true, hasArrow: true }, { children: _jsx(Icon, { as: ShareAlt, cursor: props.status === "deleted" ? "default" : "copy", onClick: props.status !== "deleted" && onCopy, "data-test": "app-copy" }) }))] })));
};
const RenameApp = ({ name, isLoading, disclosure, handleSubmit, }) => {
    const ref = React.useRef(null);
    React.useEffect(() => {
        var _a;
        (_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, [ref]);
    useOutsideClick({
        ref: ref,
        handler: () => {
            !isLoading && disclosure.onClose();
        },
    });
    return (_jsx("form", Object.assign({ onClick: (e) => e.stopPropagation(), onKeyDown: (e) => __awaiter(void 0, void 0, void 0, function* () {
            switch (e.key) {
                case "Escape":
                    disclosure.onClose();
                    break;
                case "Enter":
                    e.preventDefault();
                    yield handleSubmit(e, "rename");
                    break;
            }
        }), style: { width: "100%" } }, { children: _jsx(FormControl, { children: _jsx(Tooltip, Object.assign({ label: "Enter for submit or Esc to cancel", placement: "top", isOpen: !isLoading, hasArrow: true, shouldWrapChildren: true }, { children: _jsxs(InputGroup, { children: [_jsx(Input, { placeholder: "Enter name", ref: ref, defaultValue: name, isDisabled: isLoading, size: "sm" }), isLoading && (_jsx(InputRightElement, Object.assign({ pointerEvents: "none", height: "100%" }, { children: _jsx(CircularProgress, { isIndeterminate: true, size: 18 }) })))] }) })) }) })));
};
const AppCard = (props) => {
    const router = useRouter();
    const hasProduction = EditorContext.useSelectState((state) => state.hasProduction);
    const createApp = qoreStorageClient.table("applications").useInsertRow();
    const createRevision = qoreStorageClient.table("revisions").useInsertRow();
    const createDomain = qoreStorageClient.table("domains").useInsertRow();
    const subdomains = subdomain();
    const renameDisclosure = useDisclosure();
    const deleteDisclosure = useDisclosure();
    const toast = useToast();
    const { updateRow: updateDomain } = qoreStorageClient
        .table("domains")
        .useUpdateRow();
    const whitelistNewDomain = useUpdateWhitelist(router.query.projectID);
    const env = qoreStorageClient
        .table("environment")
        .useGetRow(props.envId, { skip: !router.isReady });
    const allAppsName = React.useMemo(() => props.allApps.data.map((i) => i.name), [props.allApps]);
    const appDomains = qoreStorageClient.table("domains").useListRow({
        condition: {
            $and: [
                {
                    appdomain: {
                        $eq: props.id,
                    },
                },
            ],
        },
    });
    const firstDomain = React.useMemo(() => {
        if (!appDomains.data.length)
            return {
                address: "none",
                description: "",
                id: "",
                name: "",
                type: null,
            };
        const domain = appDomains.data[0];
        const address = domain.address +
            (domain.type === "Hosted" ? publicRuntimeConfig.appsDomain : "");
        return Object.assign(Object.assign({}, domain), { address });
    }, [appDomains.data]);
    const getNewTitle = React.useCallback((t, i = 1) => {
        var _a;
        const titleIndex = (_a = /.+ (\(\d+\))$/g.exec(t)) === null || _a === void 0 ? void 0 : _a[1];
        const originalTitle = titleIndex
            ? t.slice(0, titleIndex.length * -1 - 1)
            : t;
        const title = `${originalTitle} (${i})`;
        return allAppsName.find((name) => name === title)
            ? getNewTitle(originalTitle, i + 1)
            : title;
    }, [props.allApps]);
    const handleDuplicateAppClick = React.useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
        var _a, _b, _c, _d, _e;
        yield Promise.resolve(props.onDuplicate((prev) => [
            ...prev,
            { data: { id: props.id, name: props.name } },
        ])).then(() => document
            .getElementById(props.id + "duplicate")
            .scrollIntoView({ behavior: "smooth" }));
        const revisions = yield qoreStorageClient.client
            .view("revision-list")
            .readRows({
            limit: 1,
            orderBy: { created_at: "DESC" },
            params: {
                appId: props.id,
                projectId: router.query.projectID,
            },
        })
            .toPromise();
        const currentApp = (_a = revisions.data) === null || _a === void 0 ? void 0 : _a.nodes[0];
        try {
            const domainResult = yield createDomain.insertRow({
                appdomain: undefined,
                address: subdomains,
                type: firstDomain.type,
            });
            const domainId = (_c = (_b = domainResult.results.data) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.id;
            if (domainId) {
                const app = yield createApp.insertRow({
                    name: getNewTitle(props.name),
                    app_environment: props.envId,
                    description: props.description,
                    project: router.query.projectID,
                });
                const appId = yield ((_e = (_d = app.results.data) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.id);
                // eslint-disable-next-line @typescript-eslint/no-unused-vars
                const revision = yield createRevision.insertRow({
                    // @ts-ignore
                    data: Object.assign(Object.assign({}, currentApp.data), { config: Object.assign(Object.assign({}, currentApp.data.config), { id: uuidv4() }) }),
                    apprevision: appId,
                    "revision-user": currentApp["revision-user"],
                });
                yield updateDomain(domainId, {
                    appdomain: appId,
                });
                yield whitelistNewDomain(subdomains);
                props.onSuccess(props.id);
            }
        }
        catch (_f) {
            toast({
                title: "Error",
                description: "Please try duplicate the app again",
                status: "error",
                duration: 3000,
                isClosable: true,
            });
            props.onFail(props.id);
        }
    }), [router.query.projectID, props.id, props.envId, subdomains, firstDomain]);
    const { updateRow: updateApp, status: loadingUpdate } = qoreStorageClient
        .table("applications")
        .useUpdateRow();
    const handleSubmit = React.useCallback((e, action) => __awaiter(void 0, void 0, void 0, function* () {
        if (action === "rename" && !e.target.value)
            return;
        if (action === "rename" && e.target.value === props.name) {
            renameDisclosure.onClose();
            return;
        }
        try {
            let payload = { name: e.target.value };
            if (action === "restore") {
                const restoreStatus = yield fetch("/api/restore-status", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: JSON.stringify({
                        appId: props.id,
                        projectId: router.query.projectID,
                    }),
                });
                if (!restoreStatus.ok)
                    throw new Error("restore failed");
                const { status } = yield restoreStatus.json();
                payload = {
                    status: status ? "published" : "unpublished",
                };
            }
            const res = yield updateApp(props.id, payload);
            if (res) {
                renameDisclosure.onClose();
                props.allApps.revalidate();
                toast({
                    title: `Success ${action}d application`,
                    status: "success",
                    duration: 5000,
                    isClosable: true,
                });
            }
        }
        catch (error) {
            toast({
                title: `Failed ${action} application`,
                description: `Oops! an error accured while ${action} application. please try again in a moment.`,
                status: "error",
                duration: 5000,
                isClosable: true,
            });
        }
    }), [props.name, props.id, env.data, router.query.projectID]);
    return (_jsxs(_Fragment, { children: [_jsxs(Box, Object.assign({ bg: "white", borderRadius: "4px", border: "1px solid #E6E9EC", height: "fit-content", padding: "16px", display: "flex", flexDirection: "column", cursor: props.status === "deleted" ? "default" : "pointer", _hover: {
                    border: "1px solid #4D93FF",
                }, onClick: () => loadingUpdate !== "loading" &&
                    props.status !== "deleted" &&
                    router.query.env !== "live" &&
                    router.push(`/apps/project/${router.query.projectID}/apps/${props.id}`), "data-test": "apps-card" }, { children: [_jsxs(Box, Object.assign({ display: "flex" }, { children: [_jsx(Box, Object.assign({ padding: "10px", marginRight: "16px", display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "#F5F5F5", borderRadius: "4px", h: "40px", w: "40px" }, { children: _jsx(Image, { src: "/assets/icon/Devices.svg", alt: "devices" }) })), _jsxs(Flex, Object.assign({ flexDir: "column", w: "full" }, { children: [_jsx(Flex, Object.assign({ justifyContent: "space-between", w: "full" }, { children: renameDisclosure.isOpen ? (_jsx(RenameApp, { name: props.name, isLoading: loadingUpdate === "loading", disclosure: renameDisclosure, handleSubmit: handleSubmit })) : (_jsxs(_Fragment, { children: [_jsx(Tooltip, Object.assign({ isDisabled: props.name.length <= 20, label: props.name }, { children: _jsxs(Text, Object.assign({ fontSize: "14px", fontWeight: "semibold", "data-test": "apps-name", color: props.status === "deleted" ? "#A2A2A2" : "grey.base" }, { children: [props.name.trim().length > 20
                                                                ? `${props.name.slice(0, 17)}...`
                                                                : props.name, _jsx(Badge, Object.assign({ colorScheme: props.status === "unpublished" ? "orange" : "gray", px: 2, textTransform: "capitalize", ml: 2, rounded: "md", hidden: router.query.env === "live" ||
                                                                    props.status === "published" ||
                                                                    !hasProduction }, { children: props.status }))] })) })), _jsxs(Menu, Object.assign({ autoSelect: false, placement: "bottom-end", isLazy: true }, { children: [_jsx(MenuButton, { as: IconButton, "aria-label": "Options", _focus: { shadow: "none" }, icon: _jsx(MoreHorizontal, {}), variant: "link", fontSize: "xl", onClick: (e) => e.stopPropagation(), hidden: router.query.env === "live" ||
                                                                loadingUpdate === "loading" }), _jsx(MenuList, Object.assign({ px: 2 }, { children: props.status !== "deleted" ? (["rename", "duplicate", "delete"].map((menu) => (_jsx(MenuItem, Object.assign({ fontSize: "14px", color: menu === "delete" ? "red" : "grey.base", onClick: (e) => __awaiter(void 0, void 0, void 0, function* () {
                                                                    e.stopPropagation();
                                                                    switch (menu) {
                                                                        case "duplicate":
                                                                            yield handleDuplicateAppClick();
                                                                            break;
                                                                        case "rename":
                                                                            renameDisclosure.onOpen();
                                                                            break;
                                                                        case "delete":
                                                                            deleteDisclosure.onOpen();
                                                                            break;
                                                                    }
                                                                }), rounded: "md", hidden: menu === "delete" && !hasProduction }, { children: _.capitalize(menu) }), menu)))) : (_jsx(MenuItem, Object.assign({ fontSize: "14px", onClick: (e) => __awaiter(void 0, void 0, void 0, function* () { return yield handleSubmit(e, "restore"); }), rounded: "md" }, { children: "Restore" }), "restore")) }))] }))] })) })), _jsx(Box, { children: _jsx(Tooltip, Object.assign({ isDisabled: props.description.length <= 30, label: props.description, hasArrow: true }, { children: _jsx(Text, Object.assign({ fontSize: "12px", color: "gray.500", "data-test": "apps-desc" }, { children: props.description.length > 30
                                                    ? props.description.slice(0, 30) + "..."
                                                    : props.description })) })) })] }))] })), _jsx(Box, Object.assign({ marginTop: "24px", maxHeight: "50px", overflowX: "hidden", overflowY: "auto", onClick: (e) => e.stopPropagation() }, { children: _jsx(AppDomainContent, { address: firstDomain.address, status: props.status }) })), _jsxs(Flex, Object.assign({ gap: 2, mt: "16px", hidden: router.query.env === "live" ||
                            props.status === "published" ||
                            !hasProduction }, { children: [_jsx(Icon, { mt: "1px", as: Information }), _jsx(Text, Object.assign({ fontSize: "12px" }, { children: props.status === "unpublished"
                                    ? "This item hasn’t exist in Live environment. Publish your project to make it live."
                                    : props.status === "deleted"
                                        ? "This item still exist in Live environment. Publish your project to completely remove it from your project."
                                        : "" }))] }))] })), _jsx(DeleteApplicationModal, { id: props.id, name: props.name, disclosure: deleteDisclosure, revalidate: props.allApps.revalidate })] }));
};
const sortBy = [
    { name: "Latest created", type: "latest" },
    { name: "Oldest created", type: "oldest" },
];
const DuplicateAppCard = (props) => {
    return (_jsx(Box, Object.assign({ id: props.app.data.id + "duplicate", bg: "white", borderRadius: "4px", border: "1px solid #E6E9EC", height: "fit-content", padding: "16px", display: "flex", flexDirection: "column", cursor: "pointer" }, { children: _jsxs(Box, { children: [_jsxs(Box, Object.assign({ display: "flex" }, { children: [_jsx(Box, Object.assign({ padding: "10px", marginRight: "16px", display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "#F4F5F5" }, { children: _jsx(Image, { src: "/assets/loader.gif", alt: "devices", w: "24px" }) })), _jsxs(Box, { children: [_jsxs(Text, Object.assign({ fontSize: "md", fontWeight: "semibold", "data-test": "apps-name", color: "gray.400" }, { children: [props.app.data.name, " Copy"] })), _jsx(Text, Object.assign({ color: "gray.400" }, { children: "Duplicating on progress..." }))] })] })), _jsx(Box, Object.assign({ marginTop: "24px", maxHeight: "50px", overflowX: "hidden", overflowY: "auto", onClick: (e) => e.stopPropagation() }, { children: _jsxs(Box, Object.assign({ display: "flex", gap: 3 }, { children: [_jsx(Icon, { color: "gray.600", as: iconsList["WarningCircle"], css: css `
                rotate: 180deg;
              `, w: "14px", h: "14px", mt: 1 }), _jsx(Text, Object.assign({ color: "gray.600" }, { children: "Duplicating app may take a while, depends on size of your app" }))] })) }))] }) })));
};
export default function AppsList() {
    var _a;
    const router = useRouter();
    const editorActions = EditorContext.useActions();
    const [sortState, setSortState] = React.useState("oldest");
    const apps = qoreStorageClient.table("applications").useListRow({
        condition: {
            app_environment: {
                project: {
                    $and: [
                        {
                            id: router.query.projectID,
                        },
                        {
                            $or: [
                                {
                                    "project-id_items": {
                                        user: "{{user.id}}",
                                        "project-role": {
                                            roles_items: {
                                                permissions: {
                                                    name: "project.detail",
                                                },
                                            },
                                        },
                                    },
                                },
                                {
                                    team: {
                                        "team-id_items": {
                                            user: "{{user.id}}",
                                            "team-role": {
                                                roles_items: {
                                                    permissions: {
                                                        name: "project.detail",
                                                    },
                                                },
                                            },
                                        },
                                    },
                                },
                                {
                                    orgs: {
                                        "organization-id_items": {
                                            user: "{{user.id}}",
                                            "organization-role": {
                                                roles_items: {
                                                    permissions: {
                                                        name: "project.detail",
                                                    },
                                                },
                                            },
                                        },
                                    },
                                },
                            ],
                        },
                    ],
                },
                name: router.query.env === "live" ? "production" : "staging",
            },
        },
        params: {
            projectId: router.query.projectID,
        },
    });
    const [duplicatedApp, setDuplicatedApp] = React.useState([]);
    const revalidate = React.useCallback(() => __awaiter(this, void 0, void 0, function* () {
        yield apps
            .revalidate()
            .then(() => document
            .getElementById(apps.data[apps.data.length - 1].id)
            .scrollIntoView({ behavior: "smooth" }));
    }), [apps]);
    const removePlaceholder = React.useCallback((appID) => setDuplicatedApp(duplicatedApp.filter((app) => app.data.id !== appID)), [apps, duplicatedApp]);
    const revalidateApps = React.useCallback((appID) => __awaiter(this, void 0, void 0, function* () {
        yield apps.revalidate();
        removePlaceholder(appID);
    }), [apps]);
    const environment = qoreStorageClient.table("environment").useListRow({
        condition: {
            project: { id: { $eq: router.query.projectID } },
            name: "production",
        },
    });
    React.useEffect(() => {
        if (environment.status === "success") {
            const production = environment.data[0];
            editorActions.setHasProduction((production === null || production === void 0 ? void 0 : production.id) ? true : false);
        }
    }, [environment]);
    const createAppDisclosure = useDisclosure();
    const sortedApps = React.useMemo(() => {
        if (!apps.data)
            return [];
        const data = [...apps.data];
        if (sortState === "latest")
            return data.reverse();
        return data;
    }, [apps.data, sortState]);
    const isLiveEnv = React.useMemo(() => {
        return router.query.env === "live";
    }, [router.query.env]);
    return (_jsxs(Box, Object.assign({ position: "fixed", overflow: "auto", inset: 0 }, { children: [_jsx(CreateApplicationModal, { disclosure: createAppDisclosure }), _jsxs(Box, Object.assign({ margin: "48px auto", maxW: "1128px" }, { children: [_jsxs(Box, Object.assign({ display: "flex", justifyContent: "space-between", alignItems: "center", mb: "26px" }, { children: [_jsx(Text, Object.assign({ fontWeight: "semibold", color: "grey.base", fontSize: "30px" }, { children: "Applications" })), _jsx(Button, Object.assign({ leftIcon: _jsx(Icon, { fontSize: "md", as: Plus }), onClick: createAppDisclosure.onOpen, colorScheme: "blue", "data-test": "create-app", hidden: isLiveEnv }, { children: "Create App" }))] })), _jsx(Box, Object.assign({ display: "flex", justifyContent: "space-between", alignItems: "center", mb: "26px" }, { children: _jsxs(HStack, Object.assign({ w: "full" }, { children: [_jsxs(HStack, Object.assign({ fontSize: "14px" }, { children: [_jsx(Text, { children: "Showing " }), _jsx(Text, Object.assign({ fontWeight: "semibold", color: "black", "data-test": "total-apps" }, { children: apps.data.length })), _jsx(Text, { children: apps.data.length > 1 ? " applications" : " application" })] })), _jsx(Spacer, {}), _jsxs(HStack, { children: [_jsx(Text, Object.assign({ fontSize: "14px" }, { children: "Sort by:" })), _jsx(Text, Object.assign({ fontSize: "14px", color: "grey.base" }, { children: (_a = sortBy.find((sort) => sort.type === sortState)) === null || _a === void 0 ? void 0 : _a.name })), _jsxs(Menu, Object.assign({ autoSelect: false, isLazy: true, placement: "bottom-end" }, { children: [_jsx(MenuButton, { as: IconButton, "aria-label": "Options", _focus: { shadow: "none" }, icon: _jsx(ChevronDown, {}), variant: "ghost", fontSize: "lg", rounded: "lg", size: "sm" }), _jsx(MenuList, Object.assign({ fontSize: "sm", px: 1 }, { children: sortBy.map((sort, idx) => (_jsx(MenuItem, Object.assign({ mb: 1, rounded: "md", onClick: () => {
                                                            setSortState(sort.type);
                                                        }, bgColor: sortState === sort.type ? "#E6F0FF" : "white", color: sortState === sort.type ? "#0065FF" : "black", _hover: {
                                                            bgColor: sortState === sort.type ? "#E6F0FF" : "grey.100",
                                                        } }, { children: sort.name }), idx))) }))] }))] })] })) })), sortedApps.length === 0 ? (_jsxs(Box, Object.assign({ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center" }, { children: [_jsx(Image, { src: "/assets/Empty-State-.svg", alt: "Empty" }), _jsx(Text, { children: `You haven't created a app yet, let's create a application` })] }))) : (_jsxs(SimpleGrid, Object.assign({ columns: 3, spacing: "16px" }, { children: [sortedApps.map((app) => {
                                return (_jsx(AppCard, { name: app.name, id: app.id, description: app.description, status: app.status, envId: app.app_environment, revalidate: revalidate, allApps: apps, onDuplicate: setDuplicatedApp, onFail: removePlaceholder, onSuccess: revalidateApps }, app.id));
                            }), duplicatedApp.map((duplicateApp, idx) => (_jsx(DuplicateAppCard, { app: duplicateApp }, idx)))] })))] }))] })));
}
//# sourceMappingURL=AppsList.js.map