// api.ts
import axios from 'axios';
import { addCSRFTokenToHeaders, getCSRFToken, generateAndStoreCSRFToken } from './utils/csrfUtils';
import { clearUserDataCache } from './utils/userCache';

// Utility function to resolve hostname to IP address
const resolveHostnameToIP = async (hostname: string): Promise<string | null> => {
    try {
        // For localhost, return as is
        if (hostname === 'localhost' || hostname === '127.0.0.1') {
            return hostname;
        }
        
        // For production domains, we can't directly resolve IP due to CORS
        // But we can show the hostname which is more useful anyway
        return hostname;
    } catch (error) {
        console.warn('Could not resolve hostname to IP:', error);
        return hostname;
    }
};

/**
 * Extract mandate/instance context from current URL
 * URL pattern: /mandates/:mandateId/:featureCode/:instanceId/...
 */
const getContextFromUrl = (): { mandateId?: string; instanceId?: string } => {
    const pathname = window.location.pathname;
    const match = pathname.match(/^\/mandates\/([^/]+)\/([^/]+)\/([^/]+)/);
    
    if (match) {
        return {
            mandateId: match[1],
            instanceId: match[3]
        };
    }
    
    return {};
};

import { getApiBaseUrl } from '../config/config';

const api = axios.create({
    baseURL: getApiBaseUrl(),
    withCredentials: true
});

// Add a request interceptor to add the auth token, context headers, and log backend IP
api.interceptors.request.use(
    async (config) => {
        // Log backend information
        const backendUrl = config.baseURL || getApiBaseUrl();
        console.log(`🌐 Communicating with backend: ${backendUrl}`);
        
        // Try to resolve and log the IP address
        if (backendUrl) {
            try {
                const url = new URL(backendUrl);
                const hostname = url.hostname;
                const resolvedIP = await resolveHostnameToIP(hostname);
                
                console.log(`📍 Backend hostname: ${hostname}`);
                console.log(`🔗 Full backend URL: ${backendUrl}`);
                console.log(`🌍 Resolved address: ${resolvedIP}`);
                
                // Log environment info
                console.log(`🏗️ Environment: ${import.meta.env.MODE}`);
                console.log(`⚙️ API Base URL: ${getApiBaseUrl()}`);
            } catch (error) {
                console.warn('Could not parse backend URL:', error);
            }
        }
        
        // Check for auth token in localStorage and add to headers
        const authToken = localStorage.getItem('authToken');
        if (authToken && config.headers) {
            config.headers.Authorization = `Bearer ${authToken}`;
            console.log('🔑 Using Bearer token for authentication');
        } else {
            // Fallback: httpOnly cookies
            console.log('🍪 Using httpOnly cookies for authentication (automatic)');
        }
        
        // Add multi-tenant context headers from URL (if not already set)
        // This ensures Feature-Instance roles are loaded for permission checks
        const context = getContextFromUrl();
        if (config.headers) {
            if (context.mandateId && !config.headers['X-Mandate-Id']) {
                config.headers['X-Mandate-Id'] = context.mandateId;
            }
            if (context.instanceId && !config.headers['X-Instance-Id']) {
                config.headers['X-Instance-Id'] = context.instanceId;
            }
        }
        
        // Add CSRF token to all requests (including GET requests for certain endpoints)
        // Some endpoints like /api/realestate/* require CSRF tokens even for GET requests
        const method = config.method?.toLowerCase();
        const url = config.url || '';
        const requiresCSRF = 
          ['post', 'put', 'patch', 'delete'].includes(method || '') ||
          url.includes('/api/realestate/');
        
        if (requiresCSRF) {
          // Ensure CSRF token exists, generate one if missing
          if (!getCSRFToken()) {
            generateAndStoreCSRFToken();
          }
          addCSRFTokenToHeaders(config.headers as Record<string, string>);
        }
        
        return config;
    },
    (error) => {
        return Promise.reject(error);
    }
);

// Add a response interceptor to handle token expiration
api.interceptors.response.use(
    (response) => response,
    async (error) => {
        if (error.response?.status === 401) {
            // Don't redirect to login if the request was to a login endpoint
            const isLoginEndpoint = error.config?.url?.includes('/login') || 
                                  error.config?.url?.includes('/api/local/login') ||
                                  error.config?.url?.includes('/api/msft/login');
            
            // Don't redirect if we're on a public auth page (prevents redirect loops and allows public pages to work)
            const pathname = window.location.pathname;
            const isOnPublicAuthPage = pathname === '/login' || 
                                       pathname.startsWith('/login') ||
                                       pathname === '/register' ||
                                       pathname.startsWith('/register') ||
                                       pathname === '/reset' ||
                                       pathname.startsWith('/reset') ||
                                       pathname === '/password-reset-request' ||
                                       pathname.startsWith('/password-reset-request') ||
                                       pathname.startsWith('/invite');
            
            if (!isLoginEndpoint && !isOnPublicAuthPage) {
                // Clear local auth data (httpOnly cookies are cleared by backend)
                sessionStorage.removeItem('auth_authority');
                clearUserDataCache();
                // Redirect to login
                window.location.href = '/login';
            }
        }
        
        // Handle rate limiting (429) - don't throw, just log and return error
        if (error.response?.status === 429) {
            console.warn('Rate limit exceeded (429). Please wait before making more requests.');
            // Don't cause cascading errors by throwing here
        }
        
        return Promise.reject(error);
    }
);

export default api;
