import { create, type StoreApi, type UseBoundStore } from 'zustand';
import { persist } from 'zustand/middleware';
import {
  login as loginService,
  register as registerService,
  logout as logoutService,
  getMe,
  type LoginRequest,
  type RegisterRequest,
} from '@/services/api/auth';
import { TokenStorage } from '@/services/tokenStorage';
import { csrfService } from '@/services/csrf';
import { broadcastSync } from '@/utils/broadcastSync';
import { logger } from '@/utils/logger';
import type { ApiError } from '@/schemas/apiSchemas';
import { parseApiError } from '@/utils/apiErrorHandler';

// INT-AUTH-002: Auth store moved from stores/auth.ts to features/auth/store/authStore.ts
// FE-TYPE-011: Fully typed store interfaces
// Action 4.1.1.5: Removed user field - user data now managed by React Query (useUser hook)
// Action 4.3.1.3: Removed _refreshUserPromise field - React Query handles deduplication
export interface AuthState {
  isAuthenticated: boolean;
  isLoading: boolean;
  error: ApiError | null;
}

export interface AuthActions {
  login: (credentials: LoginRequest) => Promise<void>;
  register: (userData: RegisterRequest) => Promise<void>;
  logout: () => Promise<void>;
  refreshUser: () => Promise<void>;
  clearError: () => void;
  setLoading: (loading: boolean) => void;
  checkAuthStatus: () => Promise<void>;
}

// FE-TYPE-011: Export store type for reuse
export type AuthStore = AuthState & AuthActions;

export const useAuthStore = create<AuthStore>()(
  persist(
    broadcastSync(
      (set) => ({
        // État initial
        // Action 4.1.1.5: user field removed - user data now managed by React Query
        // Action 4.3.1.3: _refreshUserPromise removed - React Query handles deduplication
        isAuthenticated: false,
        isLoading: false,
        error: null,

        // Actions
        login: async (credentials: LoginRequest) => {
          set({ isLoading: true, error: null });
          try {
            // Le service auth gère déjà le stockage des tokens
            // Action 4.1.1.5: user field removed - user data managed by React Query
            // Response contains user data but we don't store it (React Query handles that)
            await loginService(credentials);

            // Mettre à jour l'état de manière atomique pour éviter les problèmes de timing
            set({
              isAuthenticated: true,
              isLoading: false,
              error: null,
            });

            // Récupérer le token CSRF après login
            csrfService.refreshToken().catch((error) => {
              logger.warn('Failed to fetch CSRF token after login', {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
              });
            });
          } catch (error: unknown) {
            set({
              error: parseApiError(error),
              isLoading: false,
              isAuthenticated: false,
            });
            throw error;
          }
        },

        register: async (userData: RegisterRequest) => {
          set({ isLoading: true, error: null });
          try {
            // Le service auth gère déjà le stockage des tokens
            // Action 4.1.1.5: user field removed - user data managed by React Query
            // Response contains user data but we don't store it (React Query handles that)
            const response = await registerService(userData);

            // INT-AUTH-002: Updated to use response.token.access_token format (INT-TYPE-008)
            const isAuth = !!response.token?.access_token;

            set({
              isAuthenticated: isAuth,
              isLoading: false,
              error: null,
            });

            // Récupérer le token CSRF après register
            if (isAuth) {
              csrfService.refreshToken().catch((error) => {
                logger.warn('Failed to fetch CSRF token after register', {
                  error: error instanceof Error ? error.message : String(error),
                  stack: error instanceof Error ? error.stack : undefined,
                });
              });
            }
          } catch (error: unknown) {
            set({
              error: parseApiError(error),
              isLoading: false,
              isAuthenticated: false,
            });
            throw error;
          }
        },

        logout: async () => {
          set({ isLoading: true });
          try {
            // Le service auth gère déjà le nettoyage des tokens
            await logoutService();
          } catch (error) {
            logger.error('Logout error', {
              error: error instanceof Error ? error.message : String(error),
              stack: error instanceof Error ? error.stack : undefined,
            });
          } finally {
            // INT-016: Le cleanup du refresh proactif est géré par logoutService
            // Action 4.1.1.5: user field removed - user data managed by React Query
            // S'assurer que l'état est nettoyé même en cas d'erreur
            set({
              isAuthenticated: false,
              isLoading: false,
              error: null,
            });

            // Supprimer le token CSRF après logout
            csrfService.clearToken();
          }
        },

        refreshUser: async () => {
          // Action 4.3.1.2: Simplified using React Query - no manual promise deduplication needed
          // React Query's useUser hook handles deduplication automatically at the query level
          const currentState = useAuthStore.getState();

          if (!TokenStorage.hasTokens()) {
            // CRITIQUE FIX #2: Ne réinitialiser que si on n'était pas déjà authentifié
            if (!currentState.isAuthenticated) {
              set({ isAuthenticated: false, isLoading: false });
            }
            return;
          }

          // CRITIQUE FIX #2: Ne pas réinitialiser isAuthenticated si on était déjà authentifié
          // Cela évite les problèmes de timing après le login et la navigation
          const hasAuth = currentState.isAuthenticated;

          set({ isLoading: true });
          try {
            // Verify authentication by calling getMe()
            // User data is managed by React Query (useUser hook), not stored here
            // React Query will deduplicate this call if useUser hook is already fetching
            await getMe();
            set({
              isAuthenticated: true,
              isLoading: false,
              error: null,
            });

            // Récupérer le token CSRF après refresh user
            csrfService.refreshToken().catch((error) => {
              logger.warn('Failed to fetch CSRF token after refresh user', {
                error: error instanceof Error ? error.message : String(error),
                stack: error instanceof Error ? error.stack : undefined,
              });
            });
          } catch (error: unknown) {
            const apiError = parseApiError(error);

            // CRITIQUE FIX #2: Seulement réinitialiser pour les erreurs d'authentification (401, 1001, 1002)
            // Pour toutes les autres erreurs (réseau, timeout, etc.), PRÉSERVER l'état existant
            const errorCode =
              typeof apiError.code === 'number' ? apiError.code : 0;
            if (
              errorCode === 401 ||
              errorCode === 1001 ||
              errorCode === 1002
            ) {
              // Erreur d'authentification: nettoyer l'état
              TokenStorage.clearTokens();
              set({
                error: apiError,
                isLoading: false,
                isAuthenticated: false,
              });
            } else {
              // CRITIQUE FIX #2: Pour les autres erreurs, PRÉSERVER l'état existant
              // Cela évite les problèmes de réseau temporaires qui réinitialiseraient l'état
              set({
                error: apiError,
                isLoading: false,
                // PRÉSERVER l'état d'authentification existant
                isAuthenticated: hasAuth ? true : false,
              });
            }
          }
        },

        checkAuthStatus: async () => {
          // Action 4.1.1.5: user field removed - only check isAuthenticated
          // CRITIQUE FIX #2: Ne réinitialiser que si on n'était pas déjà authentifié
          if (!TokenStorage.hasTokens()) {
            const currentState = useAuthStore.getState();
            if (!currentState.isAuthenticated) {
              set({ isAuthenticated: false, isLoading: false });
            }
            return;
          }

          // Action 4.1.1.5: user field removed - preserve isAuthenticated state
          // CRITIQUE FIX #2: Sauvegarder l'état actuel avant toute modification
          const currentState = useAuthStore.getState();
          const hasAuth = currentState.isAuthenticated;

          set({ isLoading: true });
          try {
            // Verify authentication by calling getMe()
            // User data is managed by React Query (useUser hook), not stored here
            await getMe();
            set({
              isAuthenticated: true,
              isLoading: false,
              error: null,
            });

            // INT-016: Initialiser le refresh proactif après vérification du statut
            const { initializeProactiveRefresh } = await import(
              '@/services/tokenRefresh'
            );
            initializeProactiveRefresh();

            // Récupérer le token CSRF après check auth status
            csrfService.refreshToken().catch((error) => {
              logger.warn(
                'Failed to fetch CSRF token after check auth status',
                {
                  error: error instanceof Error ? error.message : String(error),
                  stack: error instanceof Error ? error.stack : undefined,
                },
              );
            });
          } catch (error: unknown) {
            const apiError = parseApiError(error);
            // CRITIQUE FIX #2: Seulement réinitialiser pour les erreurs d'authentification (401, 1001, 1002)
            // Pour toutes les autres erreurs (réseau, timeout, etc.), PRÉSERVER l'état existant
            const errorCode =
              typeof apiError.code === 'number' ? apiError.code : 0;
            if (errorCode === 401 || errorCode === 1001 || errorCode === 1002) {
              // Erreur d'authentification: nettoyer l'état
              TokenStorage.clearTokens();
              set({
                isAuthenticated: false,
                isLoading: false,
                error: null,
              });
            } else {
              // Action 4.1.1.5: user field removed - preserve isAuthenticated state
              // CRITIQUE FIX #2: Pour les autres erreurs, PRÉSERVER l'état existant
              // Cela évite les problèmes de réseau temporaires qui réinitialiseraient l'état
              set({
                error: apiError,
                isLoading: false,
                // PRÉSERVER l'état d'authentification existant
                isAuthenticated: hasAuth ? currentState.isAuthenticated : false,
              });
            }
          }
        },

        clearError: () => set({ error: null }),
        setLoading: (loading: boolean) => set({ isLoading: loading }),
      }),
      {
        channelName: 'auth-store',
        enabled: true,
        // FE-STATE-002: Sync authentication state across tabs
        // Action 4.1.1.5: user field removed - only sync isAuthenticated
        shouldSync: <T>(state: T, prevState: T | null) => {
          // Only sync if authentication status changed
          const authState = state as AuthState;
          const prevAuthState = prevState as AuthState | null;
          return authState.isAuthenticated !== prevAuthState?.isAuthenticated;
        },
      },
    ),
    {
      name: 'auth-storage',
      partialize: (state) => ({
        // Action 4.1.1.5: user field removed - user data managed by React Query
        isAuthenticated: state.isAuthenticated,
        // Note: Les tokens sont stockés dans TokenStorage (localStorage direct)
        // User data is now managed by React Query (useUser hook), not persisted here
      }),
    },
  ),
) as UseBoundStore<StoreApi<AuthStore>>;
