import axios from 'axios';
import type { APIEnvelope } from '../lib/types';
import { useAuthStore } from '../stores/authStore';

/**
 * Typed error class for API errors, providing structured error handling
 * across the application.
 */
export class ApiError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'ApiError';
  }
}

/**
 * Central Axios instance configured for the Stock Data Backend API.
 * - Base URL: /api/v1/
 * - Timeout: 30 seconds
 * - JSON content type
 */
const apiClient = axios.create({
  baseURL: '/api/v1/',
  timeout: 120_000,
  headers: { 'Content-Type': 'application/json' },
});

/**
 * Request interceptor: attaches JWT Bearer token from the auth store
 * to every outgoing request when a token is available.
 */
apiClient.interceptors.request.use((config) => {
  const token = useAuthStore.getState().token;
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

/**
 * Response interceptor:
 * - Success path: unwraps the { status, data, error } envelope, returning
 *   only the `data` field. Throws ApiError if envelope status is 'error'.
 * - Error path: handles 401 by clearing auth and redirecting to login.
 *   All other errors are wrapped in ApiError with a descriptive message.
 */
apiClient.interceptors.response.use(
  (response) => {
    const envelope = response.data as APIEnvelope;
    if (envelope.status === 'error') {
      throw new ApiError(envelope.error ?? 'Unknown API error');
    }
    // Return unwrapped data — callers receive the inner payload directly.
    // We override the response shape here; downstream API functions cast as needed.
    response.data = envelope.data;
    return response;
  },
  (error) => {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      useAuthStore.getState().logout();
      window.location.href = '/login';
    }
    const msg =
      error.response?.data?.error ?? error.message ?? 'Network error';
    throw new ApiError(msg);
  },
);

export default apiClient;
