import axios from 'axios';
import { Race, Tip, Schedule, Notification, UserPreferences, BetType, RaceOptions } from '../types';
import { analytics } from '../analytics';
import {
  CACHE_KEYS,
  DEFAULT_TTL,
  getCachedData,
  setCachedData,
  invalidateCache,
  invalidateAllCache,
} from './cache';

const API_BASE = process.env.EXPO_PUBLIC_BACKEND_URL || '';

const api = axios.create({
  baseURL: `${API_BASE}/api`,
  timeout: 15000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// ── JWT interceptor: attach Bearer token to every request ──
let _authToken: string | null = null;

/**
 * Set the current JWT token for the API client.
 * Called by the auth store when token changes.
 */
export function setAuthToken(token: string | null) {
  _authToken = token;
}

api.interceptors.request.use(
  (config) => {
    if (_authToken) {
      config.headers.Authorization = `Bearer ${_authToken}`;
    }
    return config;
  },
  (error) => Promise.reject(error),
);

// ── Response interceptor: handle 401 by clearing auth ──
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response?.status === 401) {
      // Token expired or invalid — clear auth state and stored token
      _authToken = null;
      try {
        const AsyncStorage = (await import('@react-native-async-storage/async-storage')).default;
        await AsyncStorage.removeItem('@tipsharks_token');
      } catch {
        // ignore storage errors
      }
      // Dynamically import to avoid circular dependency
      const { useAuthStore } = await import('../store/authStore');
      useAuthStore.getState().clearAuth();
    }
    return Promise.reject(error);
  },
);

// Races
export const getRaces = async (params?: { date?: string; track?: string; limit?: number }): Promise<Race[]> => {
  // Try cache first
  if (!params) {
    const cached = await getCachedData<Race[]>(CACHE_KEYS.RACES, DEFAULT_TTL.RACES);
    if (cached) return cached;
  }
  const response = await api.get('/races', { params });
  const data: Race[] = response.data;
  // Only cache unfiltered results
  if (!params) {
    await setCachedData(CACHE_KEYS.RACES, data, DEFAULT_TTL.RACES);
  }
  return data;
};

export const getRace = async (raceId: string): Promise<Race> => {
  // Try cache first
  const cacheKey = CACHE_KEYS.race(raceId);
  const cached = await getCachedData<Race>(cacheKey, DEFAULT_TTL.SINGLE_RACE);
  if (cached) return cached;

  const response = await api.get(`/races/${raceId}`);
  const data: Race = response.data;
  await setCachedData(cacheKey, data, DEFAULT_TTL.SINGLE_RACE);
  return data;
};

export const getNextRace = async (): Promise<Race> => {
  const response = await api.get('/races/next/upcoming');
  return response.data;
};

// Tips
export const generateTip = async (raceId: string, betType: string): Promise<Tip> => {
  const response = await api.post('/tips/generate', {
    race_id: raceId,
    bet_type: betType,
  });
  analytics.track('api_tip_generated', { race_id: raceId, bet_type: betType });
  return response.data;
};

export const saveTip = async (tip: Tip): Promise<any> => {
  const response = await api.post('/tips/save', tip);
  analytics.track('api_tip_saved', { tip_id: tip.id, race_id: tip.race_id });
  return response.data;
};

export const getSavedTips = async (): Promise<any[]> => {
  // Try cache first
  const cached = await getCachedData<any[]>(CACHE_KEYS.TIPS, DEFAULT_TTL.TIPS);
  if (cached) return cached;

  const response = await api.get('/tips/saved');
  const data: any[] = response.data;
  await setCachedData(CACHE_KEYS.TIPS, data, DEFAULT_TTL.TIPS);
  return data;
};

export const deleteSavedTip = async (tipId: string): Promise<void> => {
  await api.delete(`/tips/saved/${tipId}`);
};

// Schedules
export const createSchedule = async (data: {
  race_id: string;
  bet_type: string;
  minutes_before: number;
  channels: string[];
}): Promise<Schedule> => {
  const response = await api.post('/schedules', data);
  analytics.track('api_schedule_created', {
    race_id: data.race_id,
    minutes_before: data.minutes_before,
    bet_type: data.bet_type,
  });
  return response.data;
};

export const getSchedules = async (): Promise<Schedule[]> => {
  const response = await api.get('/schedules');
  return response.data;
};

export const cancelSchedule = async (scheduleId: string): Promise<void> => {
  await api.delete(`/schedules/${scheduleId}`);
};

// Notifications
export const getNotifications = async (): Promise<Notification[]> => {
  const response = await api.get('/notifications');
  return response.data;
};

export const markNotificationRead = async (notificationId: string): Promise<void> => {
  await api.post(`/notifications/mark-read/${notificationId}`);
};

// User Preferences
export const getPreferences = async (): Promise<UserPreferences> => {
  const response = await api.get('/user/preferences');
  return response.data;
};

export const updatePreferences = async (updates: Partial<UserPreferences>): Promise<UserPreferences> => {
  const response = await api.put('/user/preferences', updates);
  return response.data;
};

// Reference data
export const getTracks = async (racingType?: string): Promise<string[]> => {
  const params = racingType ? { racing_type: racingType } : {};
  const response = await api.get('/tracks', { params });
  // Handle both response formats
  if (response.data.tracks) {
    return response.data.tracks;
  } else if (response.data.all_tracks) {
    return response.data.all_tracks;
  }
  return [];
};

export const getTracksGrouped = async (): Promise<{ all: string[]; byType: { [key: string]: string[] } }> => {
  const response = await api.get('/tracks');
  return {
    all: response.data.all_tracks || [],
    byType: response.data.by_type || {}
  };
};

export const getBetTypes = async (): Promise<{ simple: BetType[]; advanced: BetType[] }> => {
  const response = await api.get('/bet-types');
  return response.data;
};

export const getRaceOptions = async (): Promise<RaceOptions> => {
  const response = await api.get('/race-options');
  return response.data;
};

// ── Cache management ──────────────────────────────────────

/** Clear the races list cache. */
export async function clearRaceCache(): Promise<void> {
  await invalidateCache(CACHE_KEYS.RACES);
}

/** Clear the saved-tips cache. */
export async function clearTipCache(): Promise<void> {
  await invalidateCache(CACHE_KEYS.TIPS);
}

/** Clear the single-race cache for a specific race. */
export async function clearSingleRaceCache(raceId: string): Promise<void> {
  await invalidateCache(CACHE_KEYS.race(raceId));
}

/** Clear all known caches (races, tips, single races). */
export async function clearAllCache(): Promise<void> {
  await invalidateAllCache();
}

export default api;
