//! Service d'authentification sécurisé avec cookies httpOnly
//!
//! Ce service gère:
//! - Authentification via cookies httpOnly
//! - Gestion des tokens CSRF
//! - Protection contre les attaques XSS et CSRF

import { z } from 'zod';
import type {
  ApiError,
  AuthTokens,
  LoginRequest,
  RegisterRequest,
  User,
} from '@/types';
import { csrfService } from './csrf';

// Schémas de validation
const UserSchema = z.object({
  id: z.number(),
  username: z.string(),
  email: z.string().email(),
  first_name: z.string().optional(),
  last_name: z.string().optional(),
  role: z.enum(['user', 'admin', 'super_admin']),
  is_active: z.boolean(),
  is_verified: z.boolean(),
  created_at: z.string(),
  last_login_at: z.string().optional(),
  avatar_url: z.string().optional(),
  bio: z.string().optional(),
});

const AuthTokensSchema = z.object({
  access_token: z.string(),
  refresh_token: z.string(),
  expires_in: z.number(),
});

// const _ApiErrorSchema = z.object({
//   message: z.string(),
//   code: z.string().optional(),
//   details: z.record(z.string(), z.unknown()).optional(),
// })

// Configuration
const API_BASE_URL =
  import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080/api/v1';

export class SecureAuthService {
  private static instance: SecureAuthService;
  private isAuthenticatedFlag: boolean = false;
  private user: User | null = null;

  private constructor() {
    this.checkAuthenticationStatus();
  }

  public static getInstance(): SecureAuthService {
    if (!SecureAuthService.instance) {
      SecureAuthService.instance = new SecureAuthService();
    }
    return SecureAuthService.instance;
  }

  /**
   * Vérifie le statut d'authentification via les cookies
   */
  private async checkAuthenticationStatus(): Promise<void> {
    try {
      const response = await fetch(`${API_BASE_URL}/auth/me`, {
        method: 'GET',
        credentials: 'include', // Important pour les cookies httpOnly
        headers: {
          'Content-Type': 'application/json',
          ...csrfService.getCsrfHeaders(),
        },
      });

      if (response.ok) {
        const data = await response.json();
        this.user = UserSchema.parse(data.user);
        this.isAuthenticatedFlag = true;
        console.debug('Utilisateur authentifié via cookies:', this.user);
      } else {
        this.clearAuth();
      }
    } catch (error) {
      console.warn(
        "Erreur lors de la vérification de l'authentification:",
        error
      );
      this.clearAuth();
    }
  }

  /**
   * Connexion avec cookies httpOnly
   */
  public async login(
    credentials: LoginRequest
  ): Promise<{ user: User; tokens: AuthTokens }> {
    try {
      // Récupérer le token CSRF avant la connexion
      await csrfService.refreshCsrfToken();

      const response = await fetch(`${API_BASE_URL}/auth/login`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          ...csrfService.getCsrfHeaders(),
        },
        body: JSON.stringify(credentials),
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw new ApiError(
          errorData.message || 'Erreur de connexion',
          errorData.code || 'LOGIN_ERROR'
        );
      }

      const data = await response.json();
      const user = UserSchema.parse(data.user);
      const tokens = AuthTokensSchema.parse(data.tokens);

      // Les tokens sont automatiquement stockés dans les cookies httpOnly
      // On ne les stocke pas dans localStorage pour la sécurité
      this.user = user;
      this.isAuthenticatedFlag = true;

      console.debug('Connexion réussie avec cookies httpOnly:', user);
      return { user, tokens };
    } catch (error) {
      console.error('Erreur de connexion:', error);
      this.clearAuth();
      throw error;
    }
  }

  /**
   * Inscription avec cookies httpOnly
   */
  public async register(
    userData: RegisterRequest
  ): Promise<{ user: User; tokens: AuthTokens }> {
    try {
      // Récupérer le token CSRF avant l'inscription
      await csrfService.refreshCsrfToken();

      const response = await fetch(`${API_BASE_URL}/auth/register`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          ...csrfService.getCsrfHeaders(),
        },
        body: JSON.stringify(userData),
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw new ApiError(
          errorData.message || "Erreur d'inscription",
          errorData.code || 'REGISTER_ERROR'
        );
      }

      const data = await response.json();
      const user = UserSchema.parse(data.user);
      const tokens = AuthTokensSchema.parse(data.tokens);

      this.user = user;
      this.isAuthenticatedFlag = true;

      console.debug('Inscription réussie avec cookies httpOnly:', user);
      return { user, tokens };
    } catch (error) {
      console.error("Erreur d'inscription:", error);
      this.clearAuth();
      throw error;
    }
  }

  /**
   * Déconnexion
   */
  public async logout(): Promise<void> {
    try {
      await fetch(`${API_BASE_URL}/auth/logout`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          ...csrfService.getCsrfHeaders(),
        },
      });
    } catch (error) {
      console.warn('Erreur lors de la déconnexion:', error);
    } finally {
      this.clearAuth();
    }
  }

  /**
   * Rafraîchit les informations utilisateur
   */
  public async refreshUser(): Promise<User | null> {
    try {
      const response = await fetch(`${API_BASE_URL}/auth/me`, {
        method: 'GET',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          ...csrfService.getCsrfHeaders(),
        },
      });

      if (response.ok) {
        const data = await response.json();
        this.user = UserSchema.parse(data.user);
        this.isAuthenticatedFlag = true;
        return this.user;
      } else {
        this.clearAuth();
        return null;
      }
    } catch (error) {
      console.warn("Erreur lors du rafraîchissement de l'utilisateur:", error);
      this.clearAuth();
      return null;
    }
  }

  /**
   * Rafraîchit le token d'accès
   */
  public async refreshAccessToken(): Promise<string> {
    try {
      const response = await fetch(`${API_BASE_URL}/auth/refresh`, {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          ...csrfService.getCsrfHeaders(),
        },
      });

      if (!response.ok) {
        throw new ApiError(
          'Impossible de rafraîchir le token',
          'REFRESH_ERROR'
        );
      }

      const data = await response.json();
      const tokens = AuthTokensSchema.parse(data.tokens);

      // Le nouveau token est automatiquement stocké dans les cookies httpOnly
      return tokens.access_token;
    } catch (error) {
      console.error('Erreur lors du rafraîchissement du token:', error);
      this.clearAuth();
      throw error;
    }
  }

  /**
   * Vérifie si l'utilisateur est authentifié
   */
  public isAuthenticated(): boolean {
    return this.isAuthenticatedFlag && this.user !== null;
  }

  /**
   * Obtient l'utilisateur actuel
   */
  public getCurrentUser(): User | null {
    return this.user;
  }

  /**
   * Nettoie l'état d'authentification
   */
  private clearAuth(): void {
    this.user = null;
    this.isAuthenticatedFlag = false;
    csrfService.clearCsrfToken();
  }

  /**
   * Obtient les headers d'authentification pour les requêtes
   */
  public getAuthHeaders(): Record<string, string> {
    return {
      'Content-Type': 'application/json',
      ...csrfService.getCsrfHeaders(),
    };
  }
}

// Instance singleton
export const secureAuthService = SecureAuthService.getInstance();
