import type { ApiResponse, ApiError } from '../types/api';

// API 기본 설정
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || import.meta.env.API_BASE_URL || 'http://localhost:9099/api';
const DEFAULT_TIMEOUT = 30000; // 30초

interface RequestConfig extends RequestInit {
  timeout?: number;
  token?: string;
}

class ApiClient {
  private baseUrl: string;
  private defaultHeaders: HeadersInit;

  constructor(baseUrl: string = API_BASE_URL) {
    this.baseUrl = baseUrl;
    this.defaultHeaders = {
      'Content-Type': 'application/json',
    };
  }

  /**
   * 타임아웃이 적용된 fetch 요청
   */
  private async fetchWithTimeout(
    url: string,
    config: RequestConfig = {}
  ): Promise<Response> {
    const { timeout = DEFAULT_TIMEOUT, ...fetchConfig } = config;

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);

    try {
      const response = await fetch(url, {
        ...fetchConfig,
        signal: controller.signal,
      });
      clearTimeout(timeoutId);
      return response;
    } catch (error) {
      clearTimeout(timeoutId);
      if (error instanceof Error && error.name === 'AbortError') {
        throw new Error('요청 시간이 초과되었습니다.');
      }
      throw error;
    }
  }

  /**
   * 응답 처리 및 에러 핸들링
   */
  private async handleResponse<T>(response: Response): Promise<ApiResponse<T>> {
    const contentType = response.headers.get('content-type');
    const isJson = contentType?.includes('application/json');

    if (!response.ok) {
      const errorData = isJson ? await response.json() : { message: response.statusText };
      const apiError: ApiError = {
        status: response.status,
        message: errorData.message || '요청 처리 중 오류가 발생했습니다.',
        details: errorData,
      };
      throw apiError;
    }

    const data = isJson ? await response.json() : null;
    return {
      success: true,
      data: data as T,
    };
  }

  /**
   * GET 요청
   */
  async get<T>(endpoint: string, config: RequestConfig = {}): Promise<ApiResponse<T>> {
    const { token, ...restConfig } = config;
    const headers = {
      ...this.defaultHeaders,
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...restConfig.headers,
    };

    try {
      const response = await this.fetchWithTimeout(`${this.baseUrl}${endpoint}`, {
        ...restConfig,
        method: 'GET',
        headers,
      });

      return await this.handleResponse<T>(response);
    } catch (error) {
      return this.handleError<T>(error);
    }
  }

  /**
   * POST 요청
   */
  async post<T>(
    endpoint: string,
    data?: unknown,
    config: RequestConfig = {}
  ): Promise<ApiResponse<T>> {
    const { token, ...restConfig } = config;
    const headers = {
      ...this.defaultHeaders,
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...restConfig.headers,
    };

    try {
      const response = await this.fetchWithTimeout(`${this.baseUrl}${endpoint}`, {
        ...restConfig,
        method: 'POST',
        headers,
        body: data ? JSON.stringify(data) : undefined,
      });

      return await this.handleResponse<T>(response);
    } catch (error) {
      return this.handleError<T>(error);
    }
  }

  /**
   * PUT 요청
   */
  async put<T>(
    endpoint: string,
    data?: unknown,
    config: RequestConfig = {}
  ): Promise<ApiResponse<T>> {
    const { token, ...restConfig } = config;
    const headers = {
      ...this.defaultHeaders,
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...restConfig.headers,
    };

    try {
      const response = await this.fetchWithTimeout(`${this.baseUrl}${endpoint}`, {
        ...restConfig,
        method: 'PUT',
        headers,
        body: data ? JSON.stringify(data) : undefined,
      });

      return await this.handleResponse<T>(response);
    } catch (error) {
      return this.handleError<T>(error);
    }
  }

  /**
   * DELETE 요청
   */
  async delete<T>(endpoint: string, config: RequestConfig = {}): Promise<ApiResponse<T>> {
    const { token, ...restConfig } = config;
    const headers = {
      ...this.defaultHeaders,
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...restConfig.headers,
    };

    try {
      const response = await this.fetchWithTimeout(`${this.baseUrl}${endpoint}`, {
        ...restConfig,
        method: 'DELETE',
        headers,
      });

      return await this.handleResponse<T>(response);
    } catch (error) {
      return this.handleError<T>(error);
    }
  }

  /**
   * 에러 핸들링
   */
  private handleError<T>(error: unknown): ApiResponse<T> {
    if (this.isApiError(error)) {
      return {
        success: false,
        error: error.message,
        status: error.status,
      };
    }

    if (error instanceof Error) {
      return {
        success: false,
        error: error.message,
      };
    }

    return {
      success: false,
      error: '알 수 없는 오류가 발생했습니다.',
    };
  }

  /**
   * ApiError 타입 가드
   */
  private isApiError(error: unknown): error is ApiError {
    return (
      typeof error === 'object' &&
      error !== null &&
      'status' in error &&
      'message' in error
    );
  }
}

// API 클라이언트 싱글톤 인스턴스
export const apiClient = new ApiClient();

// 기본 export
export default apiClient;
