import { TokenStorage } from '../tokenStorage';
import { apiClient } from './client';
import { parseApiError } from '@/utils/apiErrorHandler';
import { initializeProactiveRefresh, cleanupProactiveRefresh } from '../tokenRefresh';
import type { User } from '@/types';

// Re-export apiClient
export { apiClient };

/**
 * Types pour les requêtes d'authentification
 * Alignés avec FRONTEND_INTEGRATION.md
 */
export interface LoginRequest {
  email: string;
  password: string;
  remember_me?: boolean;
}

export interface RegisterRequest {
  email: string;
  password: string;
  password_confirm: string;
  username: string;
}

/**
 * Types pour les réponses d'authentification
 * Le backend retourne { success: true, data: { access_token, refresh_token, expires_in, token_type, user } }
 * Le client API fait déjà l'unwrapping, donc response.data contient directement le contenu de data
 */
export interface LoginResponse {
  access_token: string;
  refresh_token: string;
  expires_in: number;
  token_type: string;
  user: User;
}

export interface RegisterResponse {
  access_token?: string;
  refresh_token?: string;
  expires_in?: number;
  token_type?: string;
  user: User;
}

// ... existing code ...

export async function register(
  data: RegisterRequest,
): Promise<RegisterResponse> {
  try {
    // Le backend retourne { User: {...}, Token: { AccessToken, RefreshToken, ExpiresIn } }
    // ou { success: true, data: { User: {...}, Token: {...} } } après unwrapping
    const response = await apiClient.post<any>('/auth/register', {
      email: data.email,
      password: data.password,
      password_confirm: data.password_confirm,
      username: data.username,
    });

    // Extraire les tokens (même format que login)
    // Format backend: { user: {...}, token: { access_token, refresh_token, expires_in } }
    let accessToken: string | undefined;
    let refreshToken: string | undefined;
    let expiresIn: number | undefined;
    let user: User | undefined;

    // DEBUG: Log la réponse pour comprendre le format exact
    console.log('[AUTH DEBUG] Register response.data structure:', {
      hasToken: !!response.data?.token,
      hasAccessToken: !!response.data?.access_token,
      hasTokenAccessToken: !!response.data?.token?.access_token,
      keys: Object.keys(response.data || {}),
      tokenKeys: response.data?.token ? Object.keys(response.data.token) : [],
    });

    // Format backend après unwrapping: { user: {...}, token: { access_token, refresh_token, expires_in } }
    // Le backend utilise les tags JSON en snake_case (json:"access_token")
    if (response.data?.token?.access_token) {
      accessToken = response.data.token.access_token;
      refreshToken = response.data.token.refresh_token;
      expiresIn = response.data.token.expires_in;
      user = response.data.user;
      console.log('[AUTH DEBUG] Extracted from response.data.token (snake_case)');
    }
    // Format alternatif (si token est au niveau racine)
    else if (response.data?.access_token) {
      accessToken = response.data.access_token;
      refreshToken = response.data.refresh_token;
      expiresIn = response.data.expires_in;
      user = response.data.user;
      console.log('[AUTH DEBUG] Extracted from response.data (root level)');
    }
    // Format avec Token en majuscule (fallback pour compatibilité)
    else if (response.data?.Token?.AccessToken) {
      accessToken = response.data.Token.AccessToken;
      refreshToken = response.data.Token.RefreshToken;
      expiresIn = response.data.Token.ExpiresIn;
      user = response.data.User || response.data.user;
      console.log('[AUTH DEBUG] Extracted from response.data.Token (camelCase fallback)');
    } else if (response.data?.User || response.data?.user) {
      // Cas où pas de token (ex: vérification email requise)
      user = response.data.User || response.data.user;
      console.log('[AUTH DEBUG] User created without tokens (email verification likely required)');
    }

    // Stocker les tokens dans TokenStorage (CRITIQUE pour les uploads)
    if (accessToken && refreshToken) {
      TokenStorage.setTokens(accessToken, refreshToken);
      // Vérifier que les tokens sont bien stockés (pour debug)
      const storedToken = TokenStorage.getAccessToken();
      if (!storedToken) {
        console.error('[AUTH] Failed to store token in localStorage after setTokens');
      }
    } else {
      console.log('[AUTH] Registration successful but complete tokens not found. This is normal if email verification is required.');
    }

    // Retourner au format attendu par le reste de l'application
    return {
      access_token: accessToken,
      refresh_token: refreshToken,
      expires_in: expiresIn,
      token_type: accessToken ? 'Bearer' : undefined,
      user: user || response.data.user || response.data.User,
    };

  } catch (error) {
    // Le client API transforme déjà les erreurs en ApiError via parseApiError
    // Mais on s'assure que c'est bien le cas
    const apiError = parseApiError(error);
    throw apiError;
  }
}

/**
 * Connecte un utilisateur existant
 * @param data - Données de connexion (email, password, remember_me)
 * @returns Promise avec la réponse contenant l'utilisateur et les tokens
 * @throws ApiError en cas d'erreur
 */
export async function login(data: LoginRequest): Promise<LoginResponse> {
  try {
    // Le backend retourne { User: {...}, Token: { AccessToken, RefreshToken, ExpiresIn } }
    // ou { success: true, data: { User: {...}, Token: {...} } } après unwrapping
    const response = await apiClient.post<any>('/auth/login', {
      email: data.email,
      password: data.password,
      remember_me: data.remember_me || false,
    });

    // Le client API fait déjà l'unwrapping, donc response.data peut être:
    // - { User: {...}, Token: { AccessToken, RefreshToken, ExpiresIn } } (format backend)
    // - { access_token, refresh_token, expires_in, user } (format déjà transformé)

    // Extraire les tokens en supportant les deux formats
    let accessToken: string | undefined;
    let refreshToken: string | undefined;
    let expiresIn: number | undefined;
    let user: User | undefined;

    // DEBUG: Log la réponse pour comprendre le format exact
    console.log('[AUTH DEBUG] Login response.data structure:', {
      hasToken: !!response.data?.token,
      hasAccessToken: !!response.data?.access_token,
      hasTokenAccessToken: !!response.data?.token?.access_token,
      keys: Object.keys(response.data || {}),
      tokenKeys: response.data?.token ? Object.keys(response.data.token) : [],
    });

    // Format backend après unwrapping: { user: {...}, token: { access_token, refresh_token, expires_in } }
    // Le backend utilise les tags JSON en snake_case (json:"access_token")
    if (response.data?.token?.access_token) {
      accessToken = response.data.token.access_token;
      refreshToken = response.data.token.refresh_token;
      expiresIn = response.data.token.expires_in;
      user = response.data.user;
      console.log('[AUTH DEBUG] Extracted from response.data.token (snake_case)');
    }
    // Format alternatif (si token est au niveau racine)
    else if (response.data?.access_token) {
      accessToken = response.data.access_token;
      refreshToken = response.data.refresh_token;
      expiresIn = response.data.expires_in;
      user = response.data.user;
      console.log('[AUTH DEBUG] Extracted from response.data (root level)');
    }
    // Format avec Token en majuscule (fallback pour compatibilité)
    else if (response.data?.Token?.AccessToken) {
      accessToken = response.data.Token.AccessToken;
      refreshToken = response.data.Token.RefreshToken;
      expiresIn = response.data.Token.ExpiresIn;
      user = response.data.User || response.data.user;
      console.log('[AUTH DEBUG] Extracted from response.data.Token (camelCase fallback)');
    }

    // Stocker les tokens dans TokenStorage (CRITIQUE pour les uploads)
    if (accessToken && refreshToken) {
      TokenStorage.setTokens(accessToken, refreshToken);
      // Vérifier que les tokens sont bien stockés (pour debug)
      const storedToken = TokenStorage.getAccessToken();
      if (!storedToken) {
        console.error('[AUTH] Failed to store token in localStorage after setTokens');
      }
      // Stocker le flag remember_me pour référence future
      if (data.remember_me) {
        localStorage.setItem('remember_me', 'true');
      } else {
        localStorage.removeItem('remember_me');
      }

      // INT-016: Initialiser le refresh proactif après login
      initializeProactiveRefresh();
    } else {
      console.error('[AUTH] Tokens not found in login response. Response data:', JSON.stringify(response.data, null, 2));
      throw new Error('Login response missing tokens');
    }

    // Retourner au format attendu par le reste de l'application
    return {
      access_token: accessToken,
      refresh_token: refreshToken,
      expires_in: expiresIn || 3600,
      token_type: 'Bearer',
      user: user!,
    };
  } catch (error) {
    // Le client API transforme déjà les erreurs en ApiError via parseApiError
    // Mais on s'assure que c'est bien le cas
    const apiError = parseApiError(error);
    throw apiError;
  }
}

/**
 * Déconnecte l'utilisateur
 * @returns Promise qui se résout quand le logout est terminé
 */
export async function logout(): Promise<void> {
  try {
    await apiClient.post('/auth/logout');
  } catch (error) {
    // Même en cas d'erreur, on supprime les tokens localement
    // pour éviter que l'utilisateur reste bloqué
    console.warn(
      'Logout API call failed, but tokens will be cleared locally:',
      error,
    );
  } finally {
    // INT-016: Nettoyer le refresh proactif lors du logout
    cleanupProactiveRefresh();
    // Supprimer tokens du storage
    TokenStorage.clearTokens();
  }
}

/**
 * Récupère les informations de l'utilisateur actuellement authentifié
 * @returns Promise avec les informations utilisateur
 * @throws ApiError en cas d'erreur
 */
export async function getMe(): Promise<User> {
  try {
    // Le client API fait déjà l'unwrapping, donc response.data contient directement
    // { id, email, username, role, created_at, ... }
    const response = await apiClient.get<User>('/auth/me');
    return response.data;
  } catch (error) {
    const apiError = parseApiError(error);
    throw apiError;
  }
}
