/**
 * Auth store for managing authentication state
 * Uses React context for state management
 */

import { createContext, useContext, useState, useEffect, useCallback } from 'react';
import type { ReactNode } from 'react';
import type { CurrentUser } from '@/types/api/auth';
import * as authApi from '@/lib/api/auth';

// Token storage keys
const TOKEN_KEY = 'deutschlernen_token';
const REFRESH_TOKEN_KEY = 'deutschlernen_refresh_token';
const TOKEN_EXPIRY_KEY = 'deutschlernen_token_expiry';

interface AuthState {
  token: string | null;
  refreshToken: string | null;
  user: CurrentUser | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  error: string | null;
}

interface AuthContextType extends AuthState {
  login: (email: string, password: string) => Promise<void>;
  register: (username: string, email: string, password: string) => Promise<void>;
  logout: () => void;
  refreshAuthToken: () => Promise<void>;
  clearError: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

// Helper to check if token is expired
function isTokenExpired(expiry: string | null): boolean {
  if (!expiry) return true;
  const expiryDate = new Date(expiry);
  // Add 30 second buffer
  return expiryDate.getTime() - 30000 < Date.now();
}

// Helper to get token from storage
function getTokenFromStorage(): { token: string | null; refreshToken: string | null; expiry: string | null } {
  const token = localStorage.getItem(TOKEN_KEY);
  const refreshToken = localStorage.getItem(REFRESH_TOKEN_KEY);
  const expiry = localStorage.getItem(TOKEN_EXPIRY_KEY);
  return { token, refreshToken, expiry };
}

// Helper to store token
function storeToken(token: string, refreshToken: string, expiry: string): void {
  localStorage.setItem(TOKEN_KEY, token);
  localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
  localStorage.setItem(TOKEN_EXPIRY_KEY, expiry);
}

// Helper to clear token
function clearToken(): void {
  localStorage.removeItem(TOKEN_KEY);
  localStorage.removeItem(REFRESH_TOKEN_KEY);
  localStorage.removeItem(TOKEN_EXPIRY_KEY);
}

// Provider component
interface AuthProviderProps {
  children: ReactNode;
}

export function AuthProvider({ children }: AuthProviderProps) {
  const [state, setState] = useState<AuthState>({
    token: null,
    refreshToken: null,
    user: null,
    isAuthenticated: false,
    isLoading: true,
    error: null,
  });

  // Initialize from storage
  useEffect(() => {
    const initializeAuth = async () => {
      const { token, refreshToken, expiry } = getTokenFromStorage();

      if (!token || isTokenExpired(expiry)) {
        clearToken();
        setState({
          token: null,
          refreshToken: null,
          user: null,
          isAuthenticated: false,
          isLoading: false,
          error: null,
        });
        return;
      }

      try {
        // Try to get current user
        const user = await authApi.getCurrentUser(token);
        setState({
          token,
          refreshToken,
          user,
          isAuthenticated: true,
          isLoading: false,
          error: null,
        });
      } catch (err) {
        clearToken();
        setState({
          token: null,
          refreshToken: null,
          user: null,
          isAuthenticated: false,
          isLoading: false,
          error: null,
        });
      }
    };

    initializeAuth();
  }, []);

  // Login function
  const login = useCallback(async (email: string, password: string) => {
    setState(prev => ({ ...prev, isLoading: true, error: null }));

    try {
      const response = await authApi.login({ email, password });
      storeToken(response.token, response.refreshToken, response.expiresAt);

      // Get current user info
      const user = await authApi.getCurrentUser(response.token);

      setState({
        token: response.token,
        refreshToken: response.refreshToken,
        user,
        isAuthenticated: true,
        isLoading: false,
        error: null,
      });
    } catch (err) {
      setState(prev => ({
        ...prev,
        isLoading: false,
        error: err instanceof Error ? err.message : 'Login failed',
      }));
      throw err;
    }
  }, []);

  // Register function
  const register = useCallback(async (username: string, email: string, password: string) => {
    setState(prev => ({ ...prev, isLoading: true, error: null }));

    try {
      const response = await authApi.register({ username, email, password });
      storeToken(response.token, response.refreshToken, response.expiresAt);

      // Get current user info
      const user = await authApi.getCurrentUser(response.token);

      setState({
        token: response.token,
        refreshToken: response.refreshToken,
        user,
        isAuthenticated: true,
        isLoading: false,
        error: null,
      });
    } catch (err) {
      setState(prev => ({
        ...prev,
        isLoading: false,
        error: err instanceof Error ? err.message : 'Registration failed',
      }));
      throw err;
    }
  }, []);

  // Logout function
  const logout = useCallback(() => {
    clearToken();
    setState({
      token: null,
      refreshToken: null,
      user: null,
      isAuthenticated: false,
      isLoading: false,
      error: null,
    });
  }, []);

  // Refresh token function
  const refreshAuthToken = useCallback(async () => {
    const { refreshToken } = getTokenFromStorage();

    if (!refreshToken) {
      logout();
      return;
    }

    try {
      const response = await authApi.refreshToken({ refreshToken });
      storeToken(response.token, response.refreshToken, response.expiresAt);

      // Update state with new token
      setState(prev => ({
        ...prev,
        token: response.token,
        refreshToken: response.refreshToken,
      }));
    } catch (err) {
      logout();
    }
  }, [logout]);

  // Clear error function
  const clearError = useCallback(() => {
    setState(prev => ({ ...prev, error: null }));
  }, []);

  const value: AuthContextType = {
    ...state,
    login,
    register,
    logout,
    refreshAuthToken,
    clearError,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

// Hook to use auth context
export function useAuth(): AuthContextType {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
}

// Helper hook to check if user is admin
export function useIsAdmin(): boolean {
  const { user } = useAuth();
  return user?.role === 'Admin';
}

// Helper to get auth header
export function getAuthHeader(token: string | null): Record<string, string> {
  if (!token) return {};
  return { Authorization: `Bearer ${token}` };
}
