const BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1';

class ApiClient {
  private _accessToken: string | null = null;

  public set accessToken(token: string) {
    this._accessToken = token;
  }

  public get hasToken(): boolean {
    return this._accessToken !== null;
  }

  public get baseUrl(): string {
    return BASE_URL;
  }

  private getHeaders(): Record<string, string> {
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
    };

    if (this._accessToken) {
      headers['Authorization'] = `Bearer ${this._accessToken}`;
    }

    return headers;
  }

  private async handleResponse<T>(res: Response): Promise<T> {
    if (!res.ok) {
      let message: string;
      try {
        const body = await res.json();
        message = body.message || `Request failed: ${res.status}`;
      } catch {
        message = `Request failed: ${res.status} ${res.statusText}`;
      }
      throw new Error(message);
    }
    if (res.status === 204) return undefined as T;
    return res.json();
  }

  public async get<T>(url: string): Promise<T> {
    const res = await fetch(`${BASE_URL}${url}`, {
      headers: this.getHeaders(),
    });
    return this.handleResponse<T>(res);
  }

  public async post<T>(url: string, body?: unknown): Promise<T> {
    const res = await fetch(`${BASE_URL}${url}`, {
      method: 'POST',
      headers: this.getHeaders(),
      body: body ? JSON.stringify(body) : undefined,
    });
    return this.handleResponse<T>(res);
  }

  public async patch<T>(url: string, body: unknown): Promise<T> {
    const res = await fetch(`${BASE_URL}${url}`, {
      method: 'PATCH',
      headers: this.getHeaders(),
      body: JSON.stringify(body),
    });
    return this.handleResponse<T>(res);
  }

  public async delete<T = void>(url: string): Promise<T> {
    const headers: Record<string, string> = {};
    if (this._accessToken) {
      headers['Authorization'] = `Bearer ${this._accessToken}`;
    }
    const res = await fetch(`${BASE_URL}${url}`, {
      method: 'DELETE',
      headers,
    });
    return this.handleResponse<T>(res);
  }
}

export const apiClient = new ApiClient();
