/**
 * Auth Store
 * 
 * Svelte store for user authentication state, token management,
 * and user profile information.
 * 
 * Features:
 * - Centralized authentication state machine
 * - Consistent error message handling
 * - Persistent storage integration
 * - Type-safe state transitions
 */

import { writable, derived, get } from 'svelte/store';
import { browser } from '$app/environment';
import { authApi, setTokens, clearTokens, getAccessToken } from '$lib/services/api';

// ============================================================================
// Types
// ============================================================================

export type UserRole = 'superuser' | 'manager' | 'developer' | 'top_brass';

export interface User {
  id: string;
  name: string;
  email: string;
  role: UserRole;
}

export type AuthStatus = 'idle' | 'loading' | 'authenticated' | 'unauthenticated' | 'error';

export interface AuthState {
  status: AuthStatus;
  error: string | null;
  lastErrorAt: number | null;
}

// ============================================================================
// Error Messages
// ============================================================================

const ERROR_MESSAGES = {
  INVALID_CREDENTIALS: 'Invalid email or password. Please try again.',
  NETWORK_ERROR: 'Unable to connect to the server. Please check your connection.',
  SERVER_ERROR: 'An error occurred on the server. Please try again later.',
  SESSION_EXPIRED: 'Your session has expired. Please log in again.',
  UNAUTHORIZED: 'You are not authorized to access this resource.',
  UNKNOWN_ERROR: 'An unexpected error occurred. Please try again.',
  VALIDATION_ERROR: 'Please check your input and try again.',
} as const;

function getErrorMessage(error: unknown): string {
  if (error instanceof Error) {
    // Map known error patterns to consistent messages
    const message = error.message.toLowerCase();
    
    if (message.includes('invalid credentials') || message.includes('unauthorized')) {
      return ERROR_MESSAGES.INVALID_CREDENTIALS;
    }
    if (message.includes('network') || message.includes('fetch')) {
      return ERROR_MESSAGES.NETWORK_ERROR;
    }
    if (message.includes('timeout') || message.includes('504') || message.includes('503')) {
      return ERROR_MESSAGES.SERVER_ERROR;
    }
    if (message.includes('session') || message.includes('expired')) {
      return ERROR_MESSAGES.SESSION_EXPIRED;
    }
    if (message.includes('validation') || message.includes('invalid')) {
      return ERROR_MESSAGES.VALIDATION_ERROR;
    }
    
    return error.message;
  }
  
  return ERROR_MESSAGES.UNKNOWN_ERROR;
}

// ============================================================================
// Stores
// ============================================================================

function createUserStore() {
  const { subscribe, set, update } = writable<User | null>(null);

  return {
    subscribe,
    set,
    update,
    clear: () => set(null),
  };
}

export const user = createUserStore();

function createAuthStore() {
  const { subscribe, set, update } = writable<AuthState>({
    status: 'idle',
    error: null,
    lastErrorAt: null,
  });

  return {
    subscribe,
    
    // State transitions
    setIdle: () => set({ status: 'idle', error: null, lastErrorAt: null }),
    setLoading: () => update((state) => ({ ...state, status: 'loading', error: null })),
    setAuthenticated: () => set({ status: 'authenticated', error: null, lastErrorAt: null }),
    setUnauthenticated: () => set({ status: 'unauthenticated', error: null, lastErrorAt: null }),
    setError: (error: unknown) => {
      const errorMessage = getErrorMessage(error);
      set({ 
        status: 'error', 
        error: errorMessage, 
        lastErrorAt: Date.now() 
      });
    },
    
    // Utility
    clearError: () => update((state) => ({ ...state, error: null })),
    
    // Getters
    getState: () => get({ subscribe }),
  };
}

export const auth = createAuthStore();

// ============================================================================
// Derived Stores
// ============================================================================

/** Check if user is authenticated */
export const isAuthenticated = derived(
  [user, auth],
  ([$user, $auth]) => $user !== null && $auth.status === 'authenticated'
);

/** Get current user role */
export const userRole = derived(user, ($user) => $user?.role || null);

/** Check if auth is in loading state */
export const isLoading = derived(auth, ($auth) => $auth.status === 'loading');

/** Get current error message */
export const authError = derived(auth, ($auth) => $auth.error);

// ============================================================================
// Actions
// ============================================================================

export interface LoginCredentials {
  email: string;
  password: string;
}

export interface LoginResult {
  success: boolean;
  user?: User;
  error?: string;
}

/**
 * Login action
 */
export async function login(credentials: LoginCredentials): Promise<LoginResult> {
  auth.setLoading();

  try {
    const response = await authApi.login(credentials);
    
    if (response.access_token && response.refresh_token) {
      setTokens(response.access_token, response.refresh_token);
      user.set(response.data || null);
      auth.setAuthenticated();
      return { success: true, user: response.data };
    } else {
      throw new Error('Invalid response from server');
    }
  } catch (error) {
    const errorMessage = getErrorMessage(error);
    auth.setError(error);
    return { success: false, error: errorMessage };
  }
}

/**
 * Logout action
 */
export async function logout(): Promise<void> {
  auth.setLoading();

  try {
    await authApi.logout();
  } catch (error) {
    console.error('Logout API error:', error);
  } finally {
    clearTokens();
    user.clear();
    auth.setUnauthenticated();
  }
}

/**
 * Check authentication status
 */
export async function checkAuth(): Promise<boolean> {
  if (!browser) return false;

  const token = getAccessToken();
  if (!token) {
    auth.setUnauthenticated();
    user.clear();
    return false;
  }

  // If we have a token but no user, we're in a "restoring" state
  const currentUser = get(user);
  if (!currentUser) {
    // Token exists but user data is missing - try to restore from token
    // For now, we mark as authenticated and let the app fetch user data
    auth.setAuthenticated();
  }

  return true;
}

/**
 * Initialize auth state from storage
 */
export function initAuth(): void {
  if (!browser) return;

  const token = getAccessToken();
  if (token) {
    auth.setAuthenticated();
  } else {
    auth.setUnauthenticated();
  }
}

/**
 * Clear any authentication error
 */
export function clearAuthError(): void {
  auth.clearError();
}

// ============================================================================
// Role Helpers
// ============================================================================

export function hasRole(role: UserRole): boolean {
  const currentUser = get(user);
  return currentUser?.role === role;
}

export const isSuperuser = () => hasRole('superuser');
export const isManager = () => hasRole('manager');
export const isDeveloper = () => hasRole('developer');
export const isTopBrass = () => hasRole('top_brass');

// ============================================================================
// Permission Helpers
// ============================================================================

export function canManageTeamMembers(): boolean {
  return isSuperuser() || isManager();
}

export function canManageProjects(): boolean {
  return isSuperuser() || isManager();
}

export function canViewReports(): boolean {
  return isSuperuser() || isManager() || isTopBrass();
}

export function canLogActuals(): boolean {
  return isSuperuser() || isDeveloper();
}
