// src/api/client.ts
import axios, { AxiosError } from 'axios';
import { Platform } from 'react-native';
import * as SecureStore from 'expo-secure-store';
import AsyncStorage from '@react-native-async-storage/async-storage';


const API_BASE_URL = process.env.EXPO_PUBLIC_API_URL || 'https://maia.depaoli.id.au/api';
const ACCESS_TOKEN_KEY = 'maia_access_token';
const REFRESH_TOKEN_KEY = 'maia_refresh_token';

// Helper functions for storage
const storeToken = async (key: string, token: string): Promise<void> => {
    if (Platform.OS === 'web') {
        await AsyncStorage.setItem(key, token);
    } else {
        await SecureStore.setItemAsync(key, token);
    }
};

const getToken = async (key: string): Promise<string | null> => {
    if (Platform.OS === 'web') {
        return await AsyncStorage.getItem(key);
    } else {
        return await SecureStore.getItemAsync(key).catch(() => null);
    }
};

const deleteToken = async (key: string): Promise<void> => {
     if (Platform.OS === 'web') {
        await AsyncStorage.removeItem(key);
     } else {
        await SecureStore.deleteItemAsync(key).catch(() => {});
     }
};


const apiClient = axios.create({
  baseURL: API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
  timeout: 10000,
  // Remove withCredentials from default config if not needed globally
  // ...(Platform.OS === 'web' ? { withCredentials: true } : {}),
});

// --- Request Interceptor ---
apiClient.interceptors.request.use(
  async (config) => {
    const token = await getToken(ACCESS_TOKEN_KEY); // Use helper

    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    console.log('[API Client] Starting Request', config.method?.toUpperCase(), config.url);
    return config;
  },
  (error) => {
    console.error('[API Client] Request Setup Error:', error);
    return Promise.reject(error);
  }
);

// --- Modified Response Interceptor ---
apiClient.interceptors.response.use(
  (response) => {
    // Success case
    return response;
  },
  async (error: AxiosError) => { // Explicitly type error as AxiosError
    const originalRequest = error.config;

    if (error.response && originalRequest) {
      console.error('[API Client] Response Error Status:', error.response.status);
      console.error('[API Client] Response Error Data:', error.response.data);

      if (error.response.status === 401) {
        console.warn('[API Client] Unauthorized (401). Token might be expired or invalid.');

        // Prevent refresh loops if the refresh endpoint itself returns 401
        if (originalRequest.url === '/auth/refresh') {
            console.error('[API Client] Refresh token attempt failed with 401. Clearing tokens.');
            await deleteToken(ACCESS_TOKEN_KEY);
            await deleteToken(REFRESH_TOKEN_KEY); // Clear refresh token too
            delete apiClient.defaults.headers.common['Authorization'];
            // TODO: Trigger logout flow in UI
            return Promise.reject(error);
        }

        // Check if we haven't already tried to refresh for this request
        // Need to declare _retry on AxiosRequestConfig interface or use a different check
        // Using a simple check here, consider a more robust solution if needed
        if (!(originalRequest as any)._retry) {
          (originalRequest as any)._retry = true;

          try {
            const storedRefreshToken = await getToken(REFRESH_TOKEN_KEY);
            if (!storedRefreshToken) {
                console.error('[API Client] No refresh token found to attempt refresh.');
                await deleteToken(ACCESS_TOKEN_KEY); // Clear potentially invalid access token
                // TODO: Trigger logout flow in UI
                return Promise.reject(error); // Reject if no refresh token
            }

            console.log('[API Client] Attempting token refresh...');
            const refreshResponse = await apiClient.post('/auth/refresh',
              { refresh_token: storedRefreshToken }, // Send token in body
              {
                headers: { 'Content-Type': 'application/json' },
              }
            );

            if (refreshResponse.status === 200) {
              const newAccessToken = refreshResponse.data?.access_token; // Expecting only access token

              if (newAccessToken) {
                console.log('[API Client] Token refreshed successfully.');
                await storeToken(ACCESS_TOKEN_KEY, newAccessToken); // Store new access token

                // Update the default Authorization header for subsequent requests
                apiClient.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;

                // Update the Authorization header in the original request config
                if (originalRequest.headers) {
                    originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
                }

                // Retry the original request with the new access token
                return apiClient(originalRequest);
              } else {
                console.error('[API Client] Invalid token structure received during refresh:', refreshResponse.data);
                throw new Error('Invalid access token received from server during refresh.');
              }
            } else {
                 // Handle non-200 responses from refresh endpoint if necessary
                 console.error(`[API Client] Token refresh endpoint returned status ${refreshResponse.status}`);
                 throw new Error(`Refresh failed with status ${refreshResponse.status}`);
            }
          } catch (refreshError: any) {
            console.error('[API Client] Token refresh failed:', refreshError);
            // Clear tokens if refresh fails
            await deleteToken(ACCESS_TOKEN_KEY);
            await deleteToken(REFRESH_TOKEN_KEY);
            delete apiClient.defaults.headers.common['Authorization'];
            // TODO: Trigger logout flow in UI
            // Propagate the refresh error instead of the original 401
            return Promise.reject(refreshError);
          }
        } else {
             console.warn('[API Client] Already retried this request. Not attempting refresh again.');
        }

        // If retry flag was already set, or if refresh attempt failed and fell through,
        // we might still end up here. Ensure tokens are cleared if a 401 persists.
        console.log('[API Client] Clearing tokens due to persistent 401 or failed refresh.');
        await deleteToken(ACCESS_TOKEN_KEY);
        await deleteToken(REFRESH_TOKEN_KEY);
        delete apiClient.defaults.headers.common['Authorization'];
        // TODO: Trigger logout flow in UI

      } // End of 401 handling
    } else if (error.request) {
      console.log("Using API Base URL:", API_BASE_URL);
      console.error('[API Client] Network Error or No Response:', error.message);
       if (error.message.toLowerCase().includes('network error') && Platform.OS === 'web') {
           console.warn('[API Client] Hint: A "Network Error" on web often masks a CORS issue. Check browser console & backend CORS config.');
       }
    } else {
      console.error('[API Client] Request Setup Error (Interceptor):', error.message);
    }

    return Promise.reject(error);
  }
);

export default apiClient;

// Add functions to manage tokens globally if needed by UI components
export const storeTokens = async (accessToken: string, refreshToken?: string) => {
    await storeToken(ACCESS_TOKEN_KEY, accessToken);
    if (refreshToken) {
      await storeToken(REFRESH_TOKEN_KEY, refreshToken);
    }
    apiClient.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`; // Update client instance
};

export const clearTokens = async () => {
    await deleteToken(ACCESS_TOKEN_KEY);
    await deleteToken(REFRESH_TOKEN_KEY);
    delete apiClient.defaults.headers.common['Authorization']; // Clear client instance header
};

export const getRefreshToken = () => getToken(REFRESH_TOKEN_KEY);
export const getAccessToken = () => getToken(ACCESS_TOKEN_KEY);