import type { Router, RouteLocationNormalized } from "vue-router";

import type { AppRouteRecordRaw } from "@/types/router";

import { useAuthStore } from "@/stores/auth";
import { useDictStore } from "@/stores/dict";
import { usePermissionStore } from "@/stores/permission";
import { useTabsStore } from "@/stores/tabs";
import { resolveLocaleText } from "@/utils/i18n";

import { basicRoutes, notFoundRoute } from "./routes";

const MENU_HISTORY_KEY = "app-menu-history";
const MAX_HISTORY_ITEMS = 10;

interface MenuHistoryItem {
  path: string;
  title: string;
  icon?: string;
  timestamp: number;
}

function recordMenuHistory(route: RouteLocationNormalized) {
  try {
    const history: MenuHistoryItem[] = JSON.parse(
      localStorage.getItem(MENU_HISTORY_KEY) || "[]",
    );
    const title = resolveLocaleText(
      route.meta?.title as string,
      String(route.name || route.path),
    );

    const filtered = history.filter((item) => item.path !== route.path);

    filtered.unshift({
      path: route.path,
      title,
      icon: route.meta?.icon as string,
      timestamp: Date.now(),
    });

    const trimmed = filtered.slice(0, MAX_HISTORY_ITEMS);

    localStorage.setItem(MENU_HISTORY_KEY, JSON.stringify(trimmed));
  } catch {}
}

/**
 * Setup router guards
 */
export function setupRouterGuards(router: Router) {
  // Before each route navigation
  router.beforeEach(async (to, _from) => {
    const authStore = useAuthStore();
    const permissionStore = usePermissionStore();
    const tabsStore = useTabsStore();
    const dictStore = useDictStore();

    const generateDynamicRoutes = async () => {
      if (permissionStore.isRoutesGenerated) return;

      if (!authStore.user) {
        authStore.initAuth();
      }

      const accessRoutes = await permissionStore.generateRoutes(
        authStore.userRoles,
        authStore.userPermissions,
      );

      accessRoutes.forEach((route) => {
        const routeName = route.name ? String(route.name) : "";
        if (routeName && router.hasRoute(routeName)) {
          return;
        }
        router.addRoute(route);
      });

      if (!router.hasRoute("NotFound")) {
        router.addRoute(
          notFoundRoute as unknown as import("vue-router").RouteRecordRaw,
        );
      }

      // Dict API not yet available on backend
      // dictStore.loadDictData();
    };

    const initTabsIfNeeded = () => {
      if (tabsStore.tabs.length > 0) return;

      const routeSources = [
        ...basicRoutes,
        ...(permissionStore.routes as unknown as AppRouteRecordRaw[]),
      ];

      tabsStore.restoreTabsState(routeSources);

      if (tabsStore.tabs.length === 0) {
        tabsStore.initAffixTabs(routeSources);
      }
    };

    // Set page title
    if (to.meta.title) {
      const title = resolveLocaleText(
        to.meta.title as string,
        String(to.name || to.path || "Dashboard"),
      );
      document.title = `${title} - ${import.meta.env.VITE_APP_TITLE || "Antdv Next Admin"}`;
    }

    // If first refresh hits catch-all and is redirected to 404,
    // restore dynamic routes first, then retry the original target.
    const redirectedFromPath = to.redirectedFrom?.fullPath;
    const shouldRecoverFromNotFound =
      to.path === "/404" &&
      !!redirectedFromPath &&
      redirectedFromPath !== "/404" &&
      !!authStore.token &&
      !permissionStore.isRoutesGenerated;

    if (shouldRecoverFromNotFound) {
      try {
        await generateDynamicRoutes();
        initTabsIfNeeded();
        return { path: redirectedFromPath, replace: true };
      } catch (error) {
        console.error(
          "Failed to recover routes from not found redirect:",
          error,
        );
        return "/403";
      }
    }

    // If catch-all redirected to 404 but user is not logged in,
    // redirect to login instead of showing 404
    if (
      to.path === "/404" &&
      !!redirectedFromPath &&
      redirectedFromPath !== "/404" &&
      !authStore.token
    ) {
      return { path: "/login", query: { redirect: redirectedFromPath } };
    }

    // Check if route requires authentication
    const requiresAuth = to.meta.requiresAuth !== false;

    if (requiresAuth) {
      // Check if user is logged in
      if (!authStore.token) {
        return { path: "/login", query: { redirect: to.fullPath } };
      }

      // Generate dynamic routes if not already generated
      if (!permissionStore.isRoutesGenerated) {
        try {
          await generateDynamicRoutes();
          initTabsIfNeeded();

          // Continue to the target route
          return { ...to, replace: true };
        } catch (error) {
          console.error("Failed to generate routes:", error);
          return "/403";
        }
      }

      // Check permissions
      const requiredPermissions = to.meta.requiredPermissions as
        | string[]
        | undefined;
      if (
        requiredPermissions &&
        Array.isArray(requiredPermissions) &&
        requiredPermissions.length > 0
      ) {
        const hasPermission = authStore.hasAnyPermission(requiredPermissions);
        if (!hasPermission) {
          return "/403";
        }
      }

      // Check roles
      const requiredRoles = to.meta.requiredRoles as string[] | undefined;
      if (
        requiredRoles &&
        Array.isArray(requiredRoles) &&
        requiredRoles.length > 0
      ) {
        const hasRole = authStore.hasAnyRole(requiredRoles);
        if (!hasRole) {
          return "/403";
        }
      }

      initTabsIfNeeded();
    }

    // Add to tabs
    if (to.name && to.meta.requiresAuth !== false && !to.meta.hidden) {
      tabsStore.addTab(to);
    }
  });

  // After each route navigation
  router.afterEach((to) => {
    // Scroll to top
    window.scrollTo(0, 0);

    // Set active tab
    const tabsStore = useTabsStore();
    if (to.path) {
      tabsStore.setActiveTab(to.path);
    }

    // Record menu visit history
    if (to.name && to.meta.requiresAuth !== false && !to.meta.hidden) {
      recordMenuHistory(to);
    }
  });

  // On error
  router.onError((error) => {
    console.error("Router error:", error);
  });
}
