/**
 * Error interceptor: converts backend ErrorResponse objects and network errors
 * into typed ApiError / NetworkError instances.
 */

import type { AxiosInstance, AxiosError } from 'axios';
import { ApiError, AuthenticationError, NetworkError } from '../errors.js';

let captureException: ((err: unknown) => void) | undefined;
try {
  const sentryModule = '@sentry/node';
  const Sentry: { captureException: (err: unknown) => void } = await import(sentryModule);
  captureException = Sentry.captureException;
} catch { /* @sentry/node not available in this package */ }

interface BackendErrorResponse {
  message?: string;
  error?: string;
  status?: number;
  errors?: Array<{ field: string; message: string; code?: string }>;
}

export function setupErrorInterceptor(client: AxiosInstance): void {
  client.interceptors.response.use(
    undefined,
    (error: unknown) => {
      // Pass through errors that aren't axios errors (e.g. RefreshTokenExpiredError)
      const axiosError = error as AxiosError<BackendErrorResponse>;
      if (!axiosError.isAxiosError) {
        return Promise.reject(error);
      }

      // Network / timeout error (no response received)
      if (!axiosError.response) {
        const isTimeout = axiosError.code === 'ECONNABORTED';
        return Promise.reject(
          new NetworkError(
            isTimeout ? 'Request timed out' : 'Network error – is the backend running?',
            isTimeout,
          ),
        );
      }

      const { status, data } = axiosError.response;
      const message = data?.message ?? data?.error ?? axiosError.message ?? 'Unknown error';
      const validationErrors = data?.errors;

      if (status === 401 || status === 403) {
        return Promise.reject(new AuthenticationError(message, status));
      }

      if (status >= 500 && captureException) {
        captureException(new ApiError(message, status, undefined, validationErrors));
      }

      return Promise.reject(new ApiError(message, status, undefined, validationErrors));
    },
  );
}
