import { ApiError, ApiResponse, RequestOptions } from '@/types/api';

/**
 * API Client centralizado para comunicación con el backend
 * 
 * Este cliente es el ÚNICO punto de comunicación entre frontend y backend.
 * Permite migrar el backend fácilmente sin cambiar el frontend.
 */
class ApiClient {
  private baseURL: string;

  constructor(baseURL: string = '') {
    this.baseURL = baseURL;
  }

  /**
   * Petición HTTP genérica
   */
  async request<T>(endpoint: string, options: RequestOptions = {}): Promise<ApiResponse<T>> {
    const { method = 'GET', body, headers, signal } = options;

    try {
      const response = await fetch(`${this.baseURL}${endpoint}`, {
        method,
        headers: {
          'Content-Type': 'application/json',
          ...headers,
        },
        body: body ? JSON.stringify(body) : undefined,
        signal,
      });

      const data = await response.json().catch(() => ({}));

      if (!response.ok) {
        throw new ApiError(
          response.status,
          data.error || data.message || `HTTP ${response.status}: ${response.statusText}`
        );
      }

      return {
        success: true,
        data: data.data ?? data,
        message: data.message,
      };
    } catch (error) {
      if (error instanceof ApiError) {
        throw error;
      }

      if (error instanceof Error) {
        if (error.name === 'AbortError') {
          throw new ApiError(408, 'Request cancelled');
        }
        throw new ApiError(500, error.message);
      }

      throw new ApiError(500, 'Unknown error');
    }
  }

  /**
   * GET request
   */
  async get<T>(endpoint: string, params?: Record<string, string>): Promise<ApiResponse<T>> {
    // Construir URL con query params
    const url = params ? new URL(endpoint, 'http://localhost') : null;
    
    if (params && url) {
      Object.entries(params).forEach(([key, value]) => {
        url.searchParams.set(key, value);
      });
      // Retornar pathname + search (quitando el host dummy)
      return this.request<T>(url.pathname + url.search);
    }
    
    return this.request<T>(endpoint);
  }

  /**
   * POST request
   */
  async post<T>(endpoint: string, body?: unknown): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, { method: 'POST', body });
  }

  /**
   * PUT request
   */
  async put<T>(endpoint: string, body?: unknown): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, { method: 'PUT', body });
  }

  /**
   * DELETE request
   */
  async delete<T>(endpoint: string): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, { method: 'DELETE' });
  }
}

// Instancia singleton para usar en toda la aplicación
export const apiClient = new ApiClient('');
