/**
 * Typed API Client
 * FE-TYPE-010: Ensure apiClient methods are fully typed
 * 
 * Provides a fully typed wrapper around the apiClient to ensure
 * type safety for all API method calls.
 */

import { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { apiClient } from './client';
import type { ApiResponse } from '@/types/api';

/**
 * Extended request config with custom options
 */
export interface TypedRequestConfig extends InternalAxiosRequestConfig {
  _requestSchema?: unknown;
  _responseSchema?: unknown;
  _disableRetry?: boolean;
  _disableCache?: boolean;
  _enableLogging?: boolean;
  _showSuccessToast?: boolean;
  _successMessage?: string;
}

/**
 * Typed API Client Interface
 * Ensures all methods are fully typed
 */
export interface TypedApiClient {
  /**
   * GET request
   * @param url - Request URL
   * @param config - Request configuration
   * @returns Promise with typed response data
   */
  get: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;

  /**
   * POST request
   * @param url - Request URL
   * @param data - Request body data
   * @param config - Request configuration
   * @returns Promise with typed response data
   */
  post: <T = unknown, D = unknown>(
    url: string,
    data?: D,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;

  /**
   * PUT request
   * @param url - Request URL
   * @param data - Request body data
   * @param config - Request configuration
   * @returns Promise with typed response data
   */
  put: <T = unknown, D = unknown>(
    url: string,
    data?: D,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;

  /**
   * PATCH request
   * @param url - Request URL
   * @param data - Request body data
   * @param config - Request configuration
   * @returns Promise with typed response data
   */
  patch: <T = unknown, D = unknown>(
    url: string,
    data?: D,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;

  /**
   * DELETE request
   * @param url - Request URL
   * @param config - Request configuration
   * @returns Promise with typed response data
   */
  delete: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;

  /**
   * HEAD request
   * @param url - Request URL
   * @param config - Request configuration
   * @returns Promise with typed response headers
   */
  head: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;

  /**
   * OPTIONS request
   * @param url - Request URL
   * @param config - Request configuration
   * @returns Promise with typed response
   */
  options: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ) => Promise<AxiosResponse<T>>;
}

/**
 * Typed API Client implementation
 * Wraps the apiClient with full type safety
 */
export const typedApiClient: TypedApiClient = {
  get: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.get<T>(url, config);
  },

  post: <T = unknown, D = unknown>(
    url: string,
    data?: D,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.post<T, AxiosResponse<T>, D>(url, data, config);
  },

  put: <T = unknown, D = unknown>(
    url: string,
    data?: D,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.put<T, AxiosResponse<T>, D>(url, data, config);
  },

  patch: <T = unknown, D = unknown>(
    url: string,
    data?: D,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.patch<T, AxiosResponse<T>, D>(url, data, config);
  },

  delete: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.delete<T>(url, config);
  },

  head: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.head<T>(url, config);
  },

  options: <T = unknown>(
    url: string,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<T>> => {
    return apiClient.options<T>(url, config);
  },
};

/**
 * Helper type for API response data
 * Extracts the data type from an ApiResponse wrapper
 */
export type ApiResponseData<T> = T extends ApiResponse<infer D> ? D : T;

/**
 * Helper type for unwrapped API response
 * Removes the ApiResponse wrapper if present
 */
export type UnwrappedApiResponse<T> = T extends ApiResponse<infer D>
  ? D
  : T extends { data: infer D }
    ? D
    : T;

/**
 * Type-safe API request builder
 * Helps build typed API requests with proper type inference
 */
export class TypedApiRequestBuilder<TResponse = unknown, TRequest = unknown> {
  constructor(
    private method: 'get' | 'post' | 'put' | 'patch' | 'delete',
    private url: string,
  ) {}

  /**
   * Execute the request with typed data
   */
  async execute(
    data?: TRequest,
    config?: TypedRequestConfig,
  ): Promise<UnwrappedApiResponse<TResponse>> {
    let response: AxiosResponse<TResponse>;

    switch (this.method) {
      case 'get':
        response = await typedApiClient.get<TResponse>(this.url, config);
        break;
      case 'post':
        response = await typedApiClient.post<TResponse, TRequest>(
          this.url,
          data,
          config,
        );
        break;
      case 'put':
        response = await typedApiClient.put<TResponse, TRequest>(
          this.url,
          data,
          config,
        );
        break;
      case 'patch':
        response = await typedApiClient.patch<TResponse, TRequest>(
          this.url,
          data,
          config,
        );
        break;
      case 'delete':
        response = await typedApiClient.delete<TResponse>(this.url, config);
        break;
    }

    // The interceptor already unwraps the response, so data is already unwrapped
    return response.data as UnwrappedApiResponse<TResponse>;
  }

  /**
   * Execute and get full response
   */
  async executeWithResponse(
    data?: TRequest,
    config?: TypedRequestConfig,
  ): Promise<AxiosResponse<TResponse>> {
    switch (this.method) {
      case 'get':
        return typedApiClient.get<TResponse>(this.url, config);
      case 'post':
        return typedApiClient.post<TResponse, TRequest>(this.url, data, config);
      case 'put':
        return typedApiClient.put<TResponse, TRequest>(this.url, data, config);
      case 'patch':
        return typedApiClient.patch<TResponse, TRequest>(this.url, data, config);
      case 'delete':
        return typedApiClient.delete<TResponse>(this.url, config);
    }
  }
}

/**
 * Helper function to create a typed API request builder
 */
export function createTypedRequest<TResponse = unknown, TRequest = unknown>(
  method: 'get' | 'post' | 'put' | 'patch' | 'delete',
  url: string,
): TypedApiRequestBuilder<TResponse, TRequest> {
  return new TypedApiRequestBuilder<TResponse, TRequest>(method, url);
}

/**
 * Type guard to check if response is an ApiResponse wrapper
 */
export function isApiResponseWrapper<T>(
  response: unknown,
): response is ApiResponse<T> {
  return (
    typeof response === 'object' &&
    response !== null &&
    'success' in response &&
    typeof (response as any).success === 'boolean'
  );
}

/**
 * Type-safe helper to extract data from API response
 * Handles both wrapped and unwrapped responses
 */
export function extractApiData<T>(response: AxiosResponse<T>): T {
  // The interceptor already unwraps ApiResponse<T> to T
  // So we can directly return response.data
  return response.data;
}

