import { describe, expect, test } from "vitest";
import { fallbackNavigation, filterNavigationByPermission, mapBackendMenus, mergeNavigationItems } from "./menu.js";

describe("navigation menu helpers", () => {
    test("keeps requested parent menu order in fallback navigation", () => {
        expect(fallbackNavigation.map((item) => item.code)).toEqual([
            "overview",
            "app-users",
            "host-org",
            "rooms",
            "app-config",
            "resources",
            "operations",
            "payment",
            "activities",
            "games",
            "geo",
            "system",
        ]);
    });

    test("exposes activity templates below the operations activity menu", () => {
        const activities = fallbackNavigation.find((item) => item.code === "activities");
        const template = activities.children.find((item) => item.code === "activity-template");

        expect(activities.label).toBe("运营活动");
        expect(template).toMatchObject({
            label: "活动模版",
            path: "/activities/templates",
            permissionCode: "activity-template:view",
        });
    });

    test("normalizes requested parent menu order from backend menus", () => {
        const mapped = mapBackendMenus([
            { children: [], code: "system", icon: "settings", id: "system", label: "后台设置" },
            { children: [], code: "geo", icon: "map", id: "geo", label: "地区管理" },
            { children: [], code: "host-org", icon: "network", id: "host-org", label: "团队管理" },
            { children: [], code: "app-users", icon: "users", id: "app-users", label: "用户管理" },
            { children: [], code: "overview", icon: "dashboard", id: "overview", label: "总览" },
        ]);

        expect(mapped.map((item) => item.code)).toEqual(["overview", "app-users", "host-org", "geo", "system"]);
    });

    test("keeps only fallback menu items allowed by permissions", () => {
        const items = filterNavigationByPermission(
            fallbackNavigation,
            (code) => code === "agency:view" || code === "bd:view" || code === "host:view",
        );

        expect(flattenCodes(items)).not.toContain("geo");
        expect(flattenCodes(items)).toContain("host-org");
        expect(flattenCodes(items)).toContain("host-org-managers");
        expect(flattenCodes(items)).toContain("host-org-agencies");
        expect(flattenCodes(items)).toContain("host-org-hosts");
        expect(flattenCodes(items)).toContain("host-org-bd-leaders");
        expect(flattenCodes(items)).toContain("host-org-bds");
    });

    test("places country and region pages under geo menu", () => {
        const items = filterNavigationByPermission(
            fallbackNavigation,
            (code) => code === "country:view" || code === "region:view",
        );
        const geo = items.find((item) => item.code === "geo");

        expect(geo).toBeTruthy();
        expect(geo.children.map((item) => item.code)).toEqual(["host-org-countries", "host-org-regions"]);
        expect(flattenCodes(items)).not.toContain("host-org");
    });

    test("keeps the app user login log entry routable", () => {
        const items = filterNavigationByPermission(fallbackNavigation, (code) => code === "app-user:view");
        const appUsers = items.find((item) => item.code === "app-users");

        expect(appUsers.children.map((item) => item.code)).toContain("app-user-login-logs");
        expect(appUsers.children.find((item) => item.code === "app-user-login-logs").path).toBe(
            "/app/users/login-logs",
        );
    });

    test("adds missing permitted fallback children to backend menu groups", () => {
        const backendMenus = [
            {
                children: [],
                code: "host-org",
                icon: fallbackNavigation.find((item) => item.code === "host-org").icon,
                id: "host-org",
                label: "团队管理",
            },
        ];
        const fallbackMenus = filterNavigationByPermission(
            fallbackNavigation,
            (code) => code === "agency:view" || code === "bd:view",
        );
        const merged = mergeNavigationItems(backendMenus, fallbackMenus);

        expect(flattenCodes(merged)).toContain("host-org-agencies");
        expect(flattenCodes(merged)).toContain("host-org-managers");
    });

    test("places external admin users under operations with an isolated permission", () => {
        const items = filterNavigationByPermission(
            fallbackNavigation,
            (code) => code === "external-admin-user:view",
        );
        const operations = items.find((item) => item.code === "operations");

        expect(operations?.children).toEqual([
            expect.objectContaining({
                code: "operation-external-admin-users",
                label: "外管用户",
                path: "/operations/external-admin-users",
                permissionCode: "external-admin-user:view",
            }),
        ]);
    });

    test("keeps payment children under payment menu when backend menu is current", () => {
        const mapped = mapBackendMenus([
            { children: [], code: "app-config", icon: "settings", id: "app-config", label: "APP配置" },
            {
                children: [
                    {
                        code: "payment-recharge-products",
                        icon: "wallet",
                        id: "payment-recharge-products",
                        label: "内购配置",
                        path: "/payment/recharge-products",
                        permissionCode: "payment-product:view",
                    },
                    {
                        code: "payment-third-party",
                        icon: "wallet",
                        id: "payment-third-party",
                        label: "第三方支付",
                        path: "/payment/third-party",
                        permissionCode: "payment-third-party:view",
                    },
                ],
                code: "payment",
                icon: "wallet",
                id: "payment",
                label: "支付管理",
            },
        ]);
        const appConfig = mapped.find((item) => item.code === "app-config");
        const payment = mapped.find((item) => item.code === "payment");

        expect(appConfig.children || []).toEqual([]);
        expect(payment.children.map((item) => item.code)).toEqual(["payment-recharge-products", "payment-third-party"]);
        expect(payment.children.find((item) => item.code === "payment-recharge-products").path).toBe(
            "/payment/recharge-products",
        );
    });

    test("places splash screens after banners when backend menu is stale", () => {
        const backendMenus = [
            {
                children: [
                    { code: "app-config-h5", id: "app-config-h5", label: "H5配置", path: "/app-config/h5" },
                    {
                        code: "app-config-banners",
                        id: "app-config-banners",
                        label: "BANNER配置",
                        path: "/app-config/banners",
                    },
                    {
                        code: "app-config-explore",
                        id: "app-config-explore",
                        label: "Explore配置",
                        path: "/app-config/explore",
                    },
                    {
                        code: "app-config-popups",
                        id: "app-config-popups",
                        label: "弹窗配置",
                        path: "/app-config/popups",
                    },
                    {
                        code: "app-config-versions",
                        id: "app-config-versions",
                        label: "版本管理",
                        path: "/app-config/versions",
                    },
                ],
                code: "app-config",
                icon: "settings",
                id: "app-config",
                label: "APP配置",
            },
        ];
        const fallbackMenus = filterNavigationByPermission(
            fallbackNavigation,
            (code) => code === "app-config:view" || code === "full-server-notice:view",
        );
        const merged = mergeNavigationItems(mapBackendMenus(backendMenus), fallbackMenus);
        const appConfig = merged.find((item) => item.code === "app-config");

        expect(appConfig.children.map((item) => item.code)).toEqual([
            "app-config-h5",
            "app-config-banners",
            "app-config-splash-screens",
            "app-config-popups",
            "app-config-explore",
            "app-config-versions",
            "operation-full-server-notice",
        ]);
    });

    test("moves stale full server notice backend menu under app config", () => {
        const mapped = mapBackendMenus([
            {
                children: [{ code: "app-config-h5", id: "app-config-h5", label: "H5配置", path: "/app-config/h5" }],
                code: "app-config",
                icon: "settings",
                id: "app-config",
                label: "APP配置",
            },
            {
                children: [
                    {
                        code: "operation-full-server-notice",
                        icon: "campaign",
                        id: "operation-full-server-notice",
                        label: "全服通知",
                        path: "/operations/full-server-notices",
                        permissionCode: "full-server-notice:view",
                    },
                ],
                code: "operations",
                icon: "receipt",
                id: "operations",
                label: "运营管理",
            },
        ]);
        const appConfig = mapped.find((item) => item.code === "app-config");
        const operations = mapped.find((item) => item.code === "operations");

        expect(appConfig.children.map((item) => item.code)).toEqual(["app-config-h5", "operation-full-server-notice"]);
        expect(appConfig.children.find((item) => item.code === "operation-full-server-notice").path).toBe(
            "/app-config/system-message-push",
        );
        expect((operations.children || []).map((item) => item.code)).not.toContain("operation-full-server-notice");
    });

    test("adds team settings under system menu when backend menu is stale", () => {
        const backendMenus = [
            {
                children: [
                    { code: "system-users", id: "system-users", label: "后台用户", path: "/system/users" },
                    { code: "system-roles", id: "system-roles", label: "角色配置", path: "/system/roles" },
                    { code: "system-menus", id: "system-menus", label: "菜单权限", path: "/system/menus" },
                    { code: "logs-login", id: "logs-login", label: "登录日志", path: "/logs/login" },
                    { code: "logs-operations", id: "logs-operations", label: "操作日志", path: "/logs/operations" },
                ],
                code: "system",
                icon: "settings",
                id: "system",
                label: "系统设置",
            },
        ];
        const fallbackMenus = filterNavigationByPermission(fallbackNavigation, (code) => code === "team:view");
        const merged = mergeNavigationItems(mapBackendMenus(backendMenus), fallbackMenus);
        const system = merged.find((item) => item.code === "system");

        expect(system.children.map((item) => item.code)).toEqual([
            "system-users",
            "system-roles",
            "system-menus",
            "logs-login",
            "logs-operations",
            "system-teams",
        ]);
        expect(system.children.find((item) => item.code === "system-teams").path).toBe("/system/teams");
    });
});

function flattenCodes(items) {
    return items.flatMap((item) => [item.code, ...flattenCodes(item.children || [])]);
}
