import { useCallback, useMemo, useState } from "react";
import { parseForm } from "@/shared/forms/validation";
import { useAdminQuery } from "@/shared/hooks/useAdminQuery.js";
import { useConfirm } from "@/shared/ui/ConfirmProvider.jsx";
import { useToast } from "@/shared/ui/ToastProvider.jsx";
import {
    createMenu,
    createPermission,
    deleteMenu,
    deletePermission,
    listPermissions,
    listSystemMenus,
    sortMenus,
    syncPermissions,
    updateMenu,
    updateMenuVisible,
    updatePermission,
} from "@/features/menus/api";
import { useMenuAbilities } from "@/features/menus/permissions.js";
import { menuFormSchema, permissionFormSchema } from "@/features/menus/schema";

const emptyMenu = {
    code: "",
    icon: "menu",
    label: "",
    parentId: "",
    path: "",
    permissionCode: "",
    sort: 0,
    visible: true,
};

const emptyPermission = { code: "", description: "", kind: "button", name: "" };
const emptyData = { menus: [], permissions: [] };

export function useMenusPage() {
    const [menuQuery, setMenuQuery] = useState("");
    const [accessPermissionQuery, setAccessPermissionQuery] = useState("");
    const [permissionLibraryQuery, setPermissionLibraryQuery] = useState("");
    const [permissionLibraryOpen, setPermissionLibraryOpen] = useState(false);
    const [selectedMenuId, setSelectedMenuId] = useState(null);
    const [menuDrawerOpen, setMenuDrawerOpen] = useState(false);
    const [permissionDrawerOpen, setPermissionDrawerOpen] = useState(false);
    const [editingMenu, setEditingMenu] = useState(null);
    const [editingPermission, setEditingPermission] = useState(null);
    const [menuForm, setMenuForm] = useState(emptyMenu);
    const [permissionForm, setPermissionForm] = useState(emptyPermission);
    const abilities = useMenuAbilities();
    const confirm = useConfirm();
    const { showToast } = useToast();

    const queryFn = useCallback(async () => {
        const menuData = await listSystemMenus();
        const permissionData = abilities.canLoadPermissions ? await listPermissions() : [];
        return { menus: menuData || [], permissions: permissionData || [] };
    }, [abilities.canLoadPermissions]);

    const { data, error, loading, reload } = useAdminQuery(queryFn, {
        errorMessage: "加载菜单权限失败",
        initialData: emptyData,
        keepPreviousData: true,
        queryKey: ["menus", abilities.canLoadPermissions],
    });

    const flatMenus = useMemo(() => flattenMenus(data.menus || []), [data.menus]);
    const filteredFlatMenus = useMemo(() => {
        const keyword = menuQuery.trim().toLowerCase();
        if (!keyword) {
            return flatMenus;
        }
        return flatMenus.filter((menu) => {
            return [menu.label, menu.code, menu.path, menu.permissionCode].some((value) =>
                String(value || "")
                    .toLowerCase()
                    .includes(keyword),
            );
        });
    }, [flatMenus, menuQuery]);
    const filteredPermissions = useMemo(() => {
        const keyword = permissionLibraryQuery.trim().toLowerCase();
        const items = data.permissions || [];
        if (!keyword) {
            return items;
        }
        return items.filter((permission) => {
            return [permission.name, permission.code, permission.kind, permission.description].some((value) =>
                String(value || "")
                    .toLowerCase()
                    .includes(keyword),
            );
        });
    }, [data.permissions, permissionLibraryQuery]);

    const selectedMenu = useMemo(() => {
        if (!flatMenus.length) {
            return null;
        }
        const visibleSelection = filteredFlatMenus.find((menu) => menu.id === selectedMenuId);
        const currentSelection = flatMenus.find((menu) => menu.id === selectedMenuId);
        return visibleSelection || filteredFlatMenus[0] || currentSelection || flatMenus[0];
    }, [filteredFlatMenus, flatMenus, selectedMenuId]);

    const selectedPermission = useMemo(() => {
        if (!selectedMenu?.permissionCode) {
            return null;
        }
        return (data.permissions || []).find((permission) => permission.code === selectedMenu.permissionCode) || null;
    }, [data.permissions, selectedMenu]);

    const accessPermissions = useMemo(() => {
        const keyword = accessPermissionQuery.trim().toLowerCase();
        const items = (data.permissions || []).filter((permission) => permission.kind === "menu");
        if (!keyword) {
            return items;
        }
        return items.filter((permission) => {
            return [permission.name, permission.code, permission.description].some((value) =>
                String(value || "")
                    .toLowerCase()
                    .includes(keyword),
            );
        });
    }, [accessPermissionQuery, data.permissions]);

    const changeQuery = (value) => {
        setMenuQuery(value);
    };

    const resetFilters = () => {
        setMenuQuery("");
        setAccessPermissionQuery("");
        setPermissionLibraryQuery("");
    };

    const openCreateMenu = () => {
        setEditingMenu(null);
        setMenuForm(emptyMenu);
        setMenuDrawerOpen(true);
    };

    const openEditMenu = (menu) => {
        setEditingMenu(menu);
        setMenuForm({
            code: menu.code,
            icon: menu.icon || "menu",
            label: menu.label,
            parentId: menu.parentId ? String(menu.parentId) : "",
            path: menu.path || "",
            permissionCode: menu.permissionCode || "",
            sort: menu.sort || 0,
            visible: menu.visible !== false,
        });
        setMenuDrawerOpen(true);
    };

    const openCreatePermission = () => {
        setEditingPermission(null);
        setPermissionForm(emptyPermission);
        setPermissionDrawerOpen(true);
    };

    const openEditPermission = (permission) => {
        setEditingPermission(permission);
        setPermissionForm({
            code: permission.code,
            description: permission.description || "",
            kind: permission.kind,
            name: permission.name,
        });
        setPermissionDrawerOpen(true);
    };

    const submitMenu = async (event) => {
        event.preventDefault();
        try {
            const payload = parseForm(menuFormSchema, menuForm);
            if (editingMenu) {
                await updateMenu(editingMenu.id, payload);
                showToast("菜单已更新", "success");
            } else {
                await createMenu(payload);
                showToast("菜单已创建", "success");
            }
            setMenuDrawerOpen(false);
            reload();
        } catch (err) {
            showToast(err.message || "保存菜单失败", "error");
        }
    };

    const submitPermission = async (event) => {
        event.preventDefault();
        try {
            const payload = parseForm(permissionFormSchema, permissionForm);
            if (editingPermission) {
                await updatePermission(editingPermission.id, payload);
                showToast("权限已更新", "success");
            } else {
                await createPermission(payload);
                showToast("权限已创建", "success");
            }
            setPermissionDrawerOpen(false);
            reload();
        } catch (err) {
            showToast(err.message || "保存权限失败", "error");
        }
    };

    const removeMenu = async (menu) => {
        const ok = await confirm({
            confirmText: "删除",
            message: `${menu.label} 删除前需要先删除子菜单。`,
            title: "删除菜单",
            tone: "danger",
        });
        if (!ok) {
            return;
        }
        try {
            await deleteMenu(menu.id);
            showToast("菜单已删除", "success");
            reload();
        } catch (err) {
            showToast(err.message || "删除菜单失败", "error");
        }
    };

    const removePermission = async (permission) => {
        const ok = await confirm({
            confirmText: "删除",
            message: `${permission.name} 删除前不能被角色或菜单引用。`,
            title: "删除权限",
            tone: "danger",
        });
        if (!ok) {
            return;
        }
        try {
            await deletePermission(permission.id);
            showToast("权限已删除", "success");
            reload();
        } catch (err) {
            showToast(err.message || "删除权限失败", "error");
        }
    };

    const toggleVisible = async (menu) => {
        try {
            await updateMenuVisible(menu.id, !menu.visible);
            showToast("菜单状态已更新", "success");
            reload();
        } catch (err) {
            showToast(err.message || "更新菜单失败", "error");
        }
    };

    const bindMenuPermission = async (menu, permissionCode) => {
        if (!menu || !abilities.canUpdateMenu) {
            return;
        }

        try {
            const payload = parseForm(menuFormSchema, menuToForm(menu, { permissionCode }));
            await updateMenu(menu.id, payload);
            showToast(permissionCode ? "访问权限已绑定" : "访问权限已清除", "success");
            reload();
        } catch (err) {
            showToast(err.message || "保存访问权限失败", "error");
        }
    };

    const reorderMenu = async (source, target) => {
        if (!source || !target || source.id === target.id || (source.parentId || null) !== (target.parentId || null)) {
            return;
        }
        const siblings = flatMenus
            .filter((item) => (item.parentId || null) === (source.parentId || null))
            .sort((a, b) => (a.sort || 0) - (b.sort || 0) || a.id - b.id);
        const fromIndex = siblings.findIndex((item) => item.id === source.id);
        const toIndex = siblings.findIndex((item) => item.id === target.id);
        if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex) {
            return;
        }
        const reordered = [...siblings];
        const [moved] = reordered.splice(fromIndex, 1);
        reordered.splice(toIndex, 0, moved);

        try {
            await sortMenus(reordered.map((item, index) => ({ id: item.id, sort: (index + 1) * 10 })));
            showToast("菜单排序已更新", "success");
            reload();
        } catch (err) {
            showToast(err.message || "排序失败", "error");
        }
    };

    const syncDefaultPermissions = async () => {
        const ok = await confirm({ confirmText: "同步", message: "将同步系统默认权限定义。", title: "同步权限" });
        if (!ok) {
            return;
        }
        try {
            await syncPermissions();
            showToast("权限已同步", "success");
            reload();
        } catch (err) {
            showToast(err.message || "同步权限失败", "error");
        }
    };

    return {
        accessPermissionQuery,
        accessPermissions,
        abilities,
        bindMenuPermission,
        changeQuery,
        changeAccessPermissionQuery: setAccessPermissionQuery,
        changeMenuQuery: setMenuQuery,
        changePermissionLibraryQuery: setPermissionLibraryQuery,
        closeMenuDrawer: () => setMenuDrawerOpen(false),
        closePermissionDrawer: () => setPermissionDrawerOpen(false),
        closePermissionLibrary: () => setPermissionLibraryOpen(false),
        editingMenu,
        editingPermission,
        error,
        flatMenus: filteredFlatMenus,
        hasActiveFilters: Boolean(menuQuery || accessPermissionQuery || permissionLibraryQuery),
        loading,
        menuQuery,
        menuDrawerOpen,
        menuForm,
        menuTotal: flatMenus.length,
        menus: data.menus || [],
        openCreateMenu,
        openCreatePermission,
        openEditMenu,
        openEditPermission,
        openPermissionLibrary: () => setPermissionLibraryOpen(true),
        permissionLibraryOpen,
        permissionLibraryQuery,
        permissionDrawerOpen,
        permissionForm,
        permissions: filteredPermissions,
        reload,
        resetFilters,
        removeMenu,
        removePermission,
        reorderMenu,
        selectMenu: (menu) => setSelectedMenuId(menu?.id || null),
        selectedMenu,
        selectedPermission,
        setMenuForm,
        setPermissionForm,
        submitMenu,
        submitPermission,
        syncDefaultPermissions,
        toggleVisible,
    };
}

function flattenMenus(menus, depth = 0) {
    return menus.flatMap((menu) => [{ ...menu, depth }, ...flattenMenus(menu.children || [], depth + 1)]);
}

function menuToForm(menu, overrides = {}) {
    return {
        code: menu.code,
        icon: menu.icon || "menu",
        label: menu.label,
        parentId: menu.parentId ? String(menu.parentId) : "",
        path: menu.path || "",
        permissionCode: menu.permissionCode || "",
        sort: menu.sort || 0,
        visible: menu.visible !== false,
        ...overrides,
    };
}
