import { deepNormalize } from '../utils/normalize';
const API_BASE = '/api';

export class HttpClient {
  private token: string | null = null;

  setToken(token: string | null) {
    this.token = token;
  }

  async request<T>(endpoint: string, options: RequestInit & { timeout?: number } = {}): Promise<T> {
    const { timeout = 30_000, ...fetchOptions } = options;
    const controller = new AbortController();
    const timer = timeout > 0 ? setTimeout(() => controller.abort(), timeout) : undefined;

    const isFormData = fetchOptions.body instanceof FormData;
    const computedHeaders: Record<string, string> = {
      ...(this.token
        ? { Authorization: this.token.startsWith('Basic ') ? this.token : `Bearer ${this.token}` }
        : {}),
      ...(fetchOptions.headers as Record<string, string>),
    };

    if (!isFormData && !computedHeaders['Content-Type']) {
      computedHeaders['Content-Type'] = 'application/json';
    }

    let response: Response;
    try {
      response = await fetch(`${API_BASE}${endpoint}`, {
        ...fetchOptions,
        headers: computedHeaders,
        signal: controller.signal,
      });
    } catch (err) {
      clearTimeout(timer);
      if (err instanceof DOMException && err.name === 'AbortError') {
        throw new Error('Время ожидания запроса истекло');
      }
      throw err;
    }
    clearTimeout(timer);

    if (!response.ok) {
      const errorData = await response.json().catch(() => ({}));
      const errorMessage = errorData.error || errorData.message || `Request failed with status ${response.status}`;
      const err = new Error(errorMessage);
      (err as any).status = response.status;
      throw err;
    }

    // Handle empty responses (e.g., 200 OK with no body)
    const text = await response.text();
    if (!text) {
      return undefined as T;
    }

    const jsonData = JSON.parse(text);
    return deepNormalize(jsonData);
  }
}

export const httpClient = new HttpClient();
