/**
 * API service layer
 * @description Handles HTTP requests with error handling
 */

import { API_BASE_URL, API_TIMEOUT } from '@/constants/api'
import type { ApiResponse, ApiError } from '@/types'

/**
 * Base fetch wrapper with error handling
 * @description Makes HTTP requests with standardized error handling
 * @param endpoint - API endpoint path
 * @param options - Fetch options
 * @returns Promise with API response
 * @throws {ApiError} When request fails
 * @example
 * const data = await fetchApi('/users', { method: 'GET' })
 */
export async function fetchApi<T>(
    endpoint: string,
    options?: RequestInit
): Promise<ApiResponse<T>> {
    const controller = new AbortController()
    const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT)

    try {
        const response = await fetch(`${API_BASE_URL}${endpoint}`, {
            ...options,
            signal: controller.signal,
            headers: {
                'Content-Type': 'application/json',
                ...options?.headers,
            },
        })

        clearTimeout(timeoutId)

        if (!response.ok) {
            const error: ApiError = {
                message: `HTTP ${response.status}: ${response.statusText}`,
                code: `HTTP_${response.status}`,
            }
            throw error
        }

        const data = await response.json()
        return data
    } catch (error) {
        clearTimeout(timeoutId)

        if (error instanceof Error) {
            if (error.name === 'AbortError') {
                throw {
                    message: 'Request timeout',
                    code: 'TIMEOUT',
                } as ApiError
            }
            throw {
                message: error.message,
                code: 'NETWORK_ERROR',
            } as ApiError
        }

        throw error
    }
}

/**
 * GET request helper
 * @description Performs GET request
 * @param endpoint - API endpoint
 * @returns Promise with response data
 */
export async function getRequest<T>(endpoint: string): Promise<ApiResponse<T>> {
    return fetchApi<T>(endpoint, { method: 'GET' })
}

/**
 * POST request helper
 * @description Performs POST request
 * @param endpoint - API endpoint
 * @param data - Request body data
 * @returns Promise with response data
 */
export async function postRequest<T, D = unknown>(
    endpoint: string,
    data: D
): Promise<ApiResponse<T>> {
    return fetchApi<T>(endpoint, {
        method: 'POST',
        body: JSON.stringify(data),
    })
}

/**
 * PUT request helper
 * @description Performs PUT request
 * @param endpoint - API endpoint
 * @param data - Request body data
 * @returns Promise with response data
 */
export async function putRequest<T, D = unknown>(
    endpoint: string,
    data: D
): Promise<ApiResponse<T>> {
    return fetchApi<T>(endpoint, {
        method: 'PUT',
        body: JSON.stringify(data),
    })
}

/**
 * DELETE request helper
 * @description Performs DELETE request
 * @param endpoint - API endpoint
 * @returns Promise with response data
 */
export async function deleteRequest<T>(
    endpoint: string
): Promise<ApiResponse<T>> {
    return fetchApi<T>(endpoint, { method: 'DELETE' })
}
