/**
 * Authentication Store (Zustand)
 * Manages authentication state, user, and account information
 */
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { fetchAPI } from '../services/api';

type AuthErrorCode = 'ACCOUNT_REQUIRED' | 'PLAN_REQUIRED' | 'AUTH_FAILED';

function createAuthError(message: string, code: AuthErrorCode): Error & { code: AuthErrorCode } {
  const error = new Error(message) as Error & { code: AuthErrorCode };
  error.code = code;
  return error;
}

interface User {
  id: number;
  email: string;
  username: string;
  role: string;
  is_staff?: boolean;
  account?: {
    id: number;
    name: string;
    slug: string;
    credits: number;
    status: string;
    plan?: any; // plan info is optional but required for access gating
  };
}

interface AuthState {
  user: User | null;
  token: string | null;
  refreshToken: string | null;
  isAuthenticated: boolean;
  loading: boolean;
  
  // Actions
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
  register: (data: any) => Promise<void>;
  setUser: (user: User | null) => void;
  setToken: (token: string | null) => void;
  refreshToken: () => Promise<void>;
  refreshUser: () => Promise<void>;
}

export const useAuthStore = create<AuthState>()(
  persist<AuthState>(
    (set, get) => ({
      user: null,
      token: null,
      isAuthenticated: false,
      loading: false, // Always start with loading false - will be set true only during login/register
      
      login: async (email, password, rememberMe = false, forceLogout = false) => {
        set({ loading: true });
        try {
          const API_BASE_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.igny8.com/api';
          const response = await fetch(`${API_BASE_URL}/v1/auth/login/`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            credentials: 'include', // Include cookies
            body: JSON.stringify({ email, password, remember_me: rememberMe, force_logout: forceLogout }),
          });

          const data = await response.json();

          // Handle session conflict (409)
          if (response.status === 409 && data.error === 'session_conflict') {
            set({ loading: false });
            throw {
              type: 'SESSION_CONFLICT',
              message: data.message,
              existingUser: data.existing_user,
              requestedUser: data.requested_user,
            };
          }

          if (!response.ok || !data.success) {
            const message = data.error || data.message || 'Login failed';
            if (response.status === 402) {
              throw createAuthError(message, 'PLAN_REQUIRED');
            }
            if (response.status === 403) {
              throw createAuthError(message, 'ACCOUNT_REQUIRED');
            }
            throw createAuthError(message, 'AUTH_FAILED');
          }

          // Store user and JWT tokens (handle both old and new API formats)
          const responseData = data.data || data;
          // Support both formats: new (access/refresh at top level) and old (tokens.access/refresh)
          const tokens = responseData.tokens || {};
          const userData = responseData.user || data.user;

          if (!userData?.account) {
            throw createAuthError('Account not configured for this user. Please contact support.', 'ACCOUNT_REQUIRED');
          }
          if (!userData.account.plan) {
            throw createAuthError('Active subscription required. Visit igny8.com/pricing to subscribe.', 'PLAN_REQUIRED');
          }

          const newToken = responseData.access || tokens.access || data.access || null;
          const newRefreshToken = responseData.refresh || tokens.refresh || data.refresh || null;

          // CRITICAL: Set auth state AND immediately persist to localStorage
          // This prevents race conditions where API calls happen before persist middleware writes
          set({ 
            user: userData, 
            token: newToken,
            refreshToken: newRefreshToken,
            isAuthenticated: true,
            loading: false 
          });
          
          // Force immediate persist to localStorage (don't wait for Zustand middleware)
          try {
            const authState = {
              state: {
                user: userData,
                token: newToken,
                refreshToken: newRefreshToken,
                isAuthenticated: true,
                loading: false
              },
              version: 0
            };
            localStorage.setItem('auth-storage', JSON.stringify(authState));
            
            // CRITICAL: Also set tokens as separate items for API interceptor
            if (newToken) {
              localStorage.setItem('access_token', newToken);
            }
            if (newRefreshToken) {
              localStorage.setItem('refresh_token', newRefreshToken);
            }
          } catch (e) {
            console.warn('Failed to persist auth state to localStorage:', e);
          }
        } catch (error: any) {
          // ALWAYS reset loading on error - critical to prevent stuck state
          set({ loading: false });
          throw new Error(error.message || 'Login failed');
        } finally {
          // Extra safety: ensure loading is ALWAYS false after login attempt completes
          // This handles edge cases like network timeouts, browser crashes, etc.
          const current = get();
          if (current.loading) {
            set({ loading: false });
          }
        }
      },
      
      logout: () => {
        // Check if there's already a logout reason from automatic logout
        const existingReason = localStorage.getItem('logout_reason');
        
        if (!existingReason) {
          // Only store manual logout reason if no automatic reason exists
          const currentPath = typeof window !== 'undefined' ? window.location.pathname : 'unknown';
          const logoutContext = {
            code: 'MANUAL_LOGOUT',
            message: 'You have been logged out',
            path: currentPath,
            context: {
              user: get().user?.email || 'unknown',
              timestamp: new Date().toISOString(),
            },
            timestamp: new Date().toISOString(),
            source: 'manual_user_action'
          };
          
          console.error('🚪 MANUAL LOGOUT from page:', currentPath);
          
          try {
            localStorage.setItem('logout_reason', JSON.stringify(logoutContext));
            console.error('✅ Stored manual logout_reason');
          } catch (e) {
            console.error('❌ Failed to store logout reason:', e);
          }
        } else {
          console.error('⚠️ Automatic logout reason already exists, not overwriting with manual logout');
          console.error('Existing reason:', existingReason);
        }
        
        // CRITICAL: Properly clear ALL cookies to prevent session contamination
        const cookies = document.cookie.split(";");
        for (let i = 0; i < cookies.length; i++) {
          const cookie = cookies[i];
          const eqPos = cookie.indexOf("=");
          const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();
          // Clear cookie for all possible domains and paths
          document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
          document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;domain=" + window.location.hostname;
          document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;domain=." + window.location.hostname;
        }
        
        // IMPORTANT: Selectively clear auth-related localStorage items
        // DO NOT clear 'logout_reason' - it needs to persist for signin page display!
        // DO NOT use localStorage.clear() as it breaks Zustand persist middleware
        const authKeys = ['auth-storage', 'auth-store', 'site-storage', 'sector-storage', 'billing-storage', 'access_token', 'refresh_token'];
        authKeys.forEach(key => {
          try {
            localStorage.removeItem(key);
          } catch (e) {
            console.warn(`Failed to remove ${key}:`, e);
          }
        });
        
        // Clear sessionStorage
        sessionStorage.clear();
        
        // Reset auth state to initial values
        set({ 
          user: null, 
          token: null, 
          refreshToken: null, 
          isAuthenticated: false, 
          loading: false 
        });
        
        // Reset other stores that depend on auth
        try {
          // Dynamically import and reset site store
          import('./siteStore').then(({ useSiteStore }) => {
            useSiteStore.setState({ activeSite: null, loading: false, error: null });
          });
          
          // Dynamically import and reset sector store
          import('./sectorStore').then(({ useSectorStore }) => {
            useSectorStore.setState({ activeSector: null, sectors: [], loading: false, error: null });
          });
          
          // Dynamically import and reset billing store
          import('./billingStore').then(({ useBillingStore }) => {
            useBillingStore.setState({ balance: null, loading: false, error: null });
          });
        } catch (e) {
          console.warn('Failed to reset stores on logout:', e);
        }
      },
      
      register: async (registerData) => {
        set({ loading: true });
        try {
          const API_BASE_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.igny8.com/api';
          const response = await fetch(`${API_BASE_URL}/v1/auth/register/`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              ...registerData,
              password_confirm: registerData.password,  // Add password_confirm
              plan_slug: registerData.plan_slug,
            }),
          });

          const data = await response.json();

          if (!response.ok || !data.success) {
            // Handle validation errors
            const errorMessage = data.message || 
              (data.errors && typeof data.errors === 'object' 
                ? JSON.stringify(data.errors) 
                : data.errors) || 
              'Registration failed';
            throw new Error(errorMessage);
          }

          // Store user and JWT tokens (handle nested tokens structure)
          const responseData = data.data || data;
          const tokens = responseData.tokens || {};
          const userData = responseData.user || data.user;

          // Extract tokens with multiple fallbacks
          // Response format: { success: true, data: { user: {...}, tokens: { access, refresh } } }
          const newToken = 
            tokens.access || 
            responseData.access || 
            data.access || 
            data.data?.tokens?.access ||
            data.tokens?.access || 
            null;
            
          const newRefreshToken = 
            tokens.refresh || 
            responseData.refresh || 
            data.refresh || 
            data.data?.tokens?.refresh ||
            data.tokens?.refresh || 
            null;

          console.log('Registration response parsed:', {
            hasUserData: !!userData,
            hasAccessToken: !!newToken,
            hasRefreshToken: !!newRefreshToken,
            userEmail: userData?.email,
            accountId: userData?.account?.id,
            tokensLocation: tokens.access ? 'tokens.access' : 
                           responseData.access ? 'responseData.access' :
                           data.data?.tokens?.access ? 'data.data.tokens.access' : 'not found'
          });

          if (!newToken || !userData) {
            console.error('Registration succeeded but missing critical data:', {
              token: newToken,
              user: userData,
              fullResponse: data,
              parsedTokens: tokens,
              parsedResponseData: responseData
            });
            throw new Error('Registration completed but authentication failed. Please try logging in.');
          }

          // CRITICAL: Set auth state AND immediately persist to localStorage
          // This prevents race conditions where navigation happens before persist
          set({ 
            user: userData, 
            token: newToken,
            refreshToken: newRefreshToken,
            isAuthenticated: true,
            loading: false 
          });
          
          // Force immediate persist to localStorage (don't wait for Zustand middleware)
          try {
            const authState = {
              state: {
                user: userData,
                token: newToken,
                refreshToken: newRefreshToken,
                isAuthenticated: true,
                loading: false
              },
              version: 0
            };
            localStorage.setItem('auth-storage', JSON.stringify(authState));
            
            // CRITICAL: Also set tokens as separate items for API interceptor
            // This ensures fetchAPI can access tokens immediately
            if (newToken) {
              localStorage.setItem('access_token', newToken);
            }
            if (newRefreshToken) {
              localStorage.setItem('refresh_token', newRefreshToken);
            }
            
            console.log('Auth state persisted to localStorage successfully');
          } catch (e) {
            console.error('CRITICAL: Failed to persist auth state to localStorage:', e);
            throw new Error('Failed to save login session. Please try again.');
          }
          
          // Return user data for success handling
          return userData;
        } catch (error: any) {
          // ALWAYS reset loading on error - critical to prevent stuck state
          set({ loading: false });
          throw new Error(error.message || 'Registration failed');
        } finally {
          // Extra safety: ensure loading is ALWAYS false after register attempt completes
          const current = get();
          if (current.loading) {
            set({ loading: false });
          }
        }
      },
      
      setUser: (user) => {
        set({ user, isAuthenticated: !!user });
      },
      
      setToken: (token) => {
        set({ token });
      },
      
      refreshToken: async () => {
        const state = get();
        if (!state.refreshToken) {
          throw new Error('No refresh token available');
        }
        
        try {
          const API_BASE_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.igny8.com/api';
          const response = await fetch(`${API_BASE_URL}/v1/auth/refresh/`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ refresh: state.refreshToken }),
          });

          const data = await response.json();

          if (!response.ok || !data.success) {
            throw new Error(data.message || 'Token refresh failed');
          }

          // Update access token (API returns access at top level of data)
          set({ token: data.data?.access || data.access });
          
          // Also refresh user data to get latest account/plan information
          // This ensures account/plan changes are reflected immediately
          try {
            await get().refreshUser();
          } catch (userRefreshError) {
            // If user refresh fails, don't fail the token refresh
            console.warn('Failed to refresh user data during token refresh:', userRefreshError);
          }
        } catch (error: any) {
          // If refresh fails, logout user
          set({ user: null, token: null, refreshToken: null, isAuthenticated: false });
          throw new Error(error.message || 'Token refresh failed');
        }
      },
      
      refreshUser: async () => {
        const state = get();
        if (!state.token && !state.isAuthenticated) {
          throw new Error('Not authenticated');
        }
        
        try {
          const response = await fetchAPI('/v1/auth/me/');
          if (!response || !response.user) {
            throw new Error('Failed to refresh user data');
          }

          const refreshedUser = response.user;
          if (!refreshedUser.account) {
            const logoutReasonData = {
              code: 'ACCOUNT_REQUIRED',
              message: 'Account not configured for this user. Please contact support.',
              path: typeof window !== 'undefined' ? window.location.pathname : 'unknown',
              context: { 
                user_email: refreshedUser.email,
                user_id: refreshedUser.id 
              },
              timestamp: new Date().toISOString(),
              source: 'refresh_user_validation'
            };
            console.error('🚨 LOGOUT TRIGGERED - Account Required:', logoutReasonData);
            localStorage.setItem('logout_reason', JSON.stringify(logoutReasonData));
            throw createAuthError('Account not configured for this user. Please contact support.', 'ACCOUNT_REQUIRED');
          }
          if (!refreshedUser.account.plan) {
            const logoutReasonData = {
              code: 'PLAN_REQUIRED',
              message: 'Active subscription required. Visit igny8.com/pricing to subscribe.',
              path: typeof window !== 'undefined' ? window.location.pathname : 'unknown',
              context: { 
                user_email: refreshedUser.email,
                account_name: refreshedUser.account.name,
                account_id: refreshedUser.account.id 
              },
              timestamp: new Date().toISOString(),
              source: 'refresh_user_validation'
            };
            console.error('🚨 LOGOUT TRIGGERED - Plan Required:', logoutReasonData);
            localStorage.setItem('logout_reason', JSON.stringify(logoutReasonData));
            throw createAuthError('Active subscription required. Visit igny8.com/pricing to subscribe.', 'PLAN_REQUIRED');
          }

          set({ user: refreshedUser, isAuthenticated: true });
        } catch (error: any) {
          // Only logout on specific authentication/authorization errors
          // Do NOT logout on 401/403 - fetchAPI handles token refresh automatically
          // A 401 that reaches here means refresh token is invalid, which fetchAPI handles by logging out
          const isAuthError = error?.code === 'ACCOUNT_REQUIRED' || 
                             error?.code === 'PLAN_REQUIRED' ||
                             (error?.message && error.message.includes('Not authenticated'));
          
          if (isAuthError) {
            // Real authentication error - logout user
            console.warn('Authentication error during refresh, logging out:', error);
            set({ user: null, token: null, refreshToken: null, isAuthenticated: false });
          } else {
            // Network/server error or 401/403 (handled by fetchAPI) - don't logout
            // The caller (AppLayout) will handle it gracefully
            console.debug('Non-auth error during refresh (will retry):', error);
          }
          throw error;
        }
      },
    }),
    {
      name: 'auth-storage',
      // NEVER persist loading - it should always be false on app start
      partialize: (state) => ({ 
        user: state.user, 
        token: state.token,
        refreshToken: state.refreshToken,
        isAuthenticated: state.isAuthenticated,
        // Explicitly exclude loading from persistence
      }),
      // On rehydration, ensure loading is always false
      onRehydrateStorage: () => {
        return (state, error) => {
          // Always reset loading to false on rehydration - critical fix for stuck loading state
          if (state) {
            state.loading = false;
          }
          if (error) {
            console.error('Auth store rehydration error:', error);
            // If rehydration fails, ensure loading is false
            if (state) {
              state.loading = false;
            }
          }
        };
      },
    }
  )
);

