// src/client/app/main.ts
// Vue application entry point

import './index.css';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
import { useUserStore } from '../entities/user';
import { useAppConfigStore } from '../entities/appConfig';
import { usePermissionsStore } from '../entities/permissions';
import { usePermissions } from '../shared/lib/usePermissions';
import { initEntitySync } from '../processes/entitySync';

// Import route configurations from modules
import { dashboardRoutes } from '../pages/dashboard.routes';
import { sharedRoutes } from '../shared/routes';

// Create router with aggregated routes from modules
export const router = createRouter({
  history: createWebHistory(),
  routes: [...sharedRoutes, ...dashboardRoutes],
});

type DashboardRouteCandidate = {
  path: string;
  moduleName?: string;
  resource?: string;
  action?: string;
};

const DASHBOARD_ROUTE_CANDIDATES: DashboardRouteCandidate[] = [
  { path: '/dashboard/notes', moduleName: 'notes', resource: 'notes', action: 'read' },
  { path: '/dashboard/employees', moduleName: 'personnel', resource: 'personnel', action: 'read' },
  { path: '/dashboard/schedule', moduleName: 'schedule', resource: 'schedule', action: 'read' },
  { path: '/dashboard/blacklist', moduleName: 'blacklist', resource: 'blacklist', action: 'read' },
  { path: '/dashboard/access', moduleName: 'access', resource: 'access', action: 'read' },
  { path: '/dashboard/contractors', moduleName: 'contractors', resource: 'contractors', action: 'read' },
  { path: '/dashboard/rooms', moduleName: 'rooms', resource: 'rooms', action: 'read' },
  { path: '/dashboard/equipment', moduleName: 'equipment', resource: 'equipment', action: 'read' },
  { path: '/dashboard/inventory', moduleName: 'inventory', resource: 'inventory', action: 'read' },
  { path: '/dashboard/paymaster', moduleName: 'operations', resource: 'checkin', action: 'read' },
  { path: '/dashboard/tasks', moduleName: 'tasks', resource: 'tasks', action: 'read' },
];

function canAccessDashboardCandidate(
  candidate: DashboardRouteCandidate,
  enabledModules: string[],
  can: (resource: string, action: string) => boolean,
): boolean {
  if (candidate.moduleName && !enabledModules.includes(candidate.moduleName)) {
    return false;
  }

  if (candidate.resource && candidate.action && !can(candidate.resource, candidate.action)) {
    return false;
  }

  return true;
}

function getFirstAccessibleDashboardRoute(
  enabledModules: string[],
  canFn: (resource: string, action: string) => boolean,
): string | null {
  for (const candidate of DASHBOARD_ROUTE_CANDIDATES) {
    if (canAccessDashboardCandidate(candidate, enabledModules, canFn)) {
      return candidate.path;
    }
  }

  return null;
}

// Navigation guard for protected routes
router.beforeEach(async (to, _from, next) => {
  const userStore = useUserStore();
  const appConfigStore = useAppConfigStore();
  const permissionsStore = usePermissionsStore();
  const { can } = usePermissions();

  // Fetch app config (modules) on first navigation
  if (!appConfigStore.isLoaded) {
    try {
      await appConfigStore.fetchConfig();
    } catch (error) {
      console.error('[Navigation Guard] Failed to fetch app config:', error);
    }
  }

  // Fetch permissions if user is authenticated
  // Force refresh when persisted cache has empty permissions (stale cache scenario)
  const needsPermissionRefresh =
    userStore.isAuthenticated &&
    userStore.user !== null &&
    (!permissionsStore.isLoaded || permissionsStore.permissions.length === 0);

  if (needsPermissionRefresh) {
    try {
      await permissionsStore.fetchMyPermissions();
    } catch (error: any) {
      if (error?.code === 'SESSION_EXPIRED' || error?.code === 'ACCOUNT_DISABLED') {
        userStore.clearUser();
        next('/login?reason=session_expired');
        return;
      }
      console.error('[Navigation Guard] Failed to fetch permissions:', error);
    }
  }

  // Authenticated user with zero permissions = broken session, force re-login
  if (
    userStore.isAuthenticated &&
    userStore.user !== null &&
    permissionsStore.isLoaded &&
    permissionsStore.permissions.length === 0
  ) {
    console.warn('[Navigation Guard] Authenticated user has zero permissions, forcing re-login');
    userStore.clearUser();
    next('/login?reason=session_expired');
    return;
  }

  const isPublicRoute = to.meta.publicAllowed === true;
  const isAuthenticated = userStore.isAuthenticated && userStore.user !== null;

  const hasPermissions = permissionsStore.isLoaded;
  const canFn = can.value;

  // Redirect authenticated users from login page to nearest accessible dashboard section
  if (to.path === '/login') {
    if (isAuthenticated) {
      const target = getFirstAccessibleDashboardRoute(appConfigStore.enabledModules, canFn);
      next(target ?? '/dashboard');
      return;
    }

    next();
    return;
  }

  // Handle /dashboard index: redirect to first accessible child route
  if (to.path === '/dashboard' && to.matched.length > 0 && to.matched[0].path === '/dashboard') {
    if (!isAuthenticated) {
      next('/login?reason=session_expired');
      return;
    }
    const target = getFirstAccessibleDashboardRoute(appConfigStore.enabledModules, canFn);
    if (target) {
      next(target);
    } else {
      next();
    }
    return;
  }

  // Handle explicit /404 and non-matched routes (e.g., HMR route mismatch)
  if (to.path === '/404' || to.matched.length === 0) {
    if (isAuthenticated) {
      const target = getFirstAccessibleDashboardRoute(appConfigStore.enabledModules, canFn);
      if (target) {
        next(target);
      } else {
        next();
      }
      return;
    }

    next('/login?reason=session_expired');
    return;
  }

  // Check if route requires authentication
  if (to.meta.requiresAuth) {
    const isAuth = userStore.checkAuth();
    const hasUserData = userStore.user !== null;

    if (!isAuth || !hasUserData) {
      userStore.clearUser();
      const reason = hasUserData ? 'session_invalid' : 'session_expired';
      next(`/login?reason=${reason}`);
      return;
    }
  }

  // Module guard
  const routeModuleName = to.meta.moduleName as string | undefined;
  if (routeModuleName) {
    if (!appConfigStore.isModuleEnabled(routeModuleName)) {
      const moduleNames: Record<string, string> = {
        notes: 'Заметки',
        personnel: 'Сотрудники',
        schedule: 'График смен',
        blacklist: 'Черный список',
        reference_books: 'Справочники',
        rooms: 'База номеров',
        operations: 'Текущие операции',
        checkin: 'Заезд/Выезд',
        paymaster: 'Кассовый отчёт',
        cleaning: 'График уборки',
        tasks: 'Задачи',
      };
      const moduleDisplayName = moduleNames[routeModuleName] || routeModuleName;
      alert(`Модуль "${moduleDisplayName}" отключен администратором`);
      console.warn(`[Navigation Guard] Module "${routeModuleName}" is disabled, redirecting to dashboard`);

      const target = getFirstAccessibleDashboardRoute(appConfigStore.enabledModules, canFn);
      if (target) {
        next(target);
      } else {
        next('/dashboard');
      }
      return;
    }
  }

  // Permission guard — only enforce when permissions are successfully loaded
  const routeResource = to.meta.resource as string | undefined;
  const routeAction = to.meta.action as string | 'read' | undefined;
  const effectiveRouteResource = routeResource ?? routeModuleName;
  const effectiveRouteAction = routeAction ?? (effectiveRouteResource ? 'read' : undefined);

  if (effectiveRouteResource && effectiveRouteAction && hasPermissions) {
    if (isPublicRoute && !userStore.isAuthenticated) {
      next();
      return;
    }

    if (userStore.isAuthenticated) {
      if (!canFn(effectiveRouteResource, effectiveRouteAction)) {
        console.warn(
          `[Navigation Guard] User does not have permission: ${effectiveRouteResource}:${effectiveRouteAction}`,
        );

        const target = getFirstAccessibleDashboardRoute(appConfigStore.enabledModules, canFn);

        if (target && target !== to.path) {
          next(target);
        } else {
          // No accessible route at all — let the page render (backend will enforce access)
          console.warn('[Navigation Guard] No accessible fallback route, allowing navigation');
          next();
        }
        return;
      }
    }
  }

  next();
});

const app = createApp(App);
const pinia = createPinia();

pinia.use(piniaPluginPersistedstate);

app.use(pinia);
initEntitySync(); // <-- Инициализация межмодульной синхронизации

// Инициализируем глобальный обработчик для очистки пользователя (используется в api.client.ts)
const userStore = useUserStore();
window.clearUser = () => userStore.clearUser();

// Pre-hydration of permissions for persisted authenticated session
const permissionsStore = usePermissionsStore();
if (
  userStore.isAuthenticated &&
  userStore.user &&
  (!permissionsStore.isLoaded || permissionsStore.permissions.length === 0)
) {
  try {
    await permissionsStore.fetchMyPermissions();
  } catch (error: any) {
    if (error?.code !== 'SESSION_EXPIRED' && error?.code !== 'ACCOUNT_DISABLED') {
      console.error('[Bootstrap] Failed to prefetch permissions:', error);
    }
  }

  // If permissions are still empty after successful fetch — broken session
  if (permissionsStore.permissions.length === 0) {
    console.warn('[Bootstrap] Authenticated user has zero permissions, forcing re-login');
    userStore.clearUser();
  }
}
app.use(router);
app.mount('#app');
