import axios, { AxiosError, type AxiosInstance } from 'axios';
import { ApiClientError, apiBaseUrl, handlers } from './base';

export const http: AxiosInstance = axios.create({
  baseURL: apiBaseUrl,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
  },
});

function extractMessage(details: unknown, fallback: string): string {
  if (typeof details === 'object' && details) {
    if ('message' in details && typeof details.message === 'string') {
      return details.message;
    }
    if ('detail' in details && typeof details.detail === 'string') {
      return details.detail;
    }
    if ('error' in details && typeof details.error === 'object' && details.error) {
      const zodError = details.error as Record<string, unknown>;
      if (Array.isArray(zodError.issues) && zodError.issues.length > 0) {
        const firstIssue = zodError.issues[0] as { message?: string };
        if (typeof firstIssue.message === 'string') return firstIssue.message;
      }
      if (typeof zodError.message === 'string') {
        try {
          const parsed = JSON.parse(zodError.message);
          if (
            Array.isArray(parsed) &&
            parsed.length > 0 &&
            typeof parsed[0]?.message === 'string'
          ) {
            return parsed[0].message;
          }
        } catch {
          /* not JSON, use raw string */
        }
        return zodError.message;
      }
    }
  }
  return fallback;
}

function normalizeError(error: unknown): ApiClientError {
  if (error instanceof ApiClientError) return error;

  if (axios.isAxiosError(error)) {
    const status = error.response?.status;
    const details = error.response?.data;

    return new ApiClientError(extractMessage(details, error.message || 'Request failed'), {
      status,
      details,
      causeError: error,
    });
  }

  if (error instanceof Error) {
    return new ApiClientError(error.message, { causeError: error });
  }

  return new ApiClientError('Error inesperado.', { causeError: error });
}

http.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    const normalized = normalizeError(error);

    if (normalized.status === 401 && handlers.onUnauthorized) {
      await handlers.onUnauthorized(normalized);
    }

    if (normalized.status === 403 && handlers.onForbidden) {
      await handlers.onForbidden(normalized);
    }

    if (handlers.onError) {
      await handlers.onError(normalized);
    }

    return Promise.reject(normalized);
  }
);
