/**
 * API Service
 * Handles all communication with the server API endpoints
 * Note: URLValidator is available globally via /static/js/security/url-validator.js
 */

// Base URL for API - guard against duplicate script loading (same pattern as urls.js)
// Uses window property to survive duplicate <script> loads without redeclaring.
const API_BASE_URL = (typeof window !== 'undefined' && typeof window.API_BASE_URL !== 'undefined')
    ? window.API_BASE_URL
    : '/api';

/**
 * Get CSRF token from meta tag
 * @returns {string} The CSRF token
 */
function getCsrfToken() {
    const metaTag = document.querySelector('meta[name="csrf-token"]');
    return metaTag ? metaTag.getAttribute('content') : '';
}

/**
 * Get the full URL for an API endpoint
 * @param {string} path - The API path (without leading slash)
 * @returns {string} The full API URL
 */
function getApiUrl(path) {
    return `${API_BASE_URL}/${path}`;
}

/**
 * Generic fetch with error handling and timeout support
 * @param {string} url - The URL to fetch
 * @param {Object} options - Fetch options
 * @param {number} [options.timeout=30000] - Request timeout in milliseconds (default: 30s)
 * @returns {Promise<any>} The parsed response data
 */
async function fetchWithErrorHandling(url, options = {}) {
    const { timeout = 30000, ...fetchOptions } = options;
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);

    try {
        const csrfToken = getCsrfToken();
        const response = await fetch(url, {
            ...fetchOptions,
            signal: controller.signal,
            headers: {
                'Content-Type': 'application/json',
                ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {}),
                ...(fetchOptions.headers || {})
            }
        });

        // Handle non-200 responses
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            throw new Error(errorData.message || errorData.error || `API Error: ${response.status} ${response.statusText}`);
        }

        // Parse the response
        return await response.json();
    } catch (error) {
        if (error.name === 'AbortError') {
            throw new Error('Request timed out');
        }
        SafeLogger.error('API Error:', error);
        throw error;
    } finally {
        clearTimeout(timeoutId);
    }
}

/**
 * Helper method to perform POST requests with JSON data
 * @param {string} path - API path
 * @param {Object} data - JSON data to send
 * @returns {Promise<any>} Response data
 */
async function postJSON(path, data) {
    return fetchWithErrorHandling(path, {
        method: 'POST',
        body: JSON.stringify(data)
    });
}

/**
 * Start a new research
 * @param {string} query - The research query
 * @param {string} mode - The research mode (quick/detailed)
 * @returns {Promise<Object>} The research response with ID
 */
async function startResearch(query, mode) {
    return postJSON(URLS.API.START_RESEARCH, { query, mode });
}

/**
 * Get a research status by ID
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The research status
 */
async function getResearchStatus(researchId) {
    return fetchWithErrorHandling(URLBuilder.researchStatus(researchId));
}

/**
 * Get research details
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The research details
 */
async function getResearchDetails(researchId) {
    return fetchWithErrorHandling(URLBuilder.researchDetails(researchId));
}

/**
 * Get research logs
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The research logs
 */
async function getResearchLogs(researchId) {
    return fetchWithErrorHandling(URLBuilder.researchLogs(researchId));
}

/**
 * Get research history
 * @returns {Promise<Array>} The research history
 */
async function getResearchHistory() {
    return fetchWithErrorHandling(URLS.API.HISTORY);
}

/**
 * Get research report
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The research report
 */
async function getReport(researchId) {
    return fetchWithErrorHandling(URLBuilder.researchReport(researchId));
}

/**
 * Terminate a research
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The termination response
 */
async function terminateResearch(researchId) {
    return postJSON(URLBuilder.terminateResearch(researchId), {});
}

/**
 * Delete a research
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The deletion response
 */
async function deleteResearch(researchId) {
    return fetchWithErrorHandling(URLBuilder.deleteResearch(researchId), {
        method: 'DELETE'
    });
}

/**
 * Clear all research history
 * @returns {Promise<Object>} The response
 */
async function clearResearchHistory() {
    return postJSON(URLS.API.CLEAR_HISTORY, {});
}

/**
 * Open a file location in the system file explorer
 * @param {string} path - Path to open
 * @returns {Promise<Object>} The response
 */
async function openFileLocation(path) {
    return postJSON('/api/open_file_location', { path });
}

/**
 * Save raw configuration
 * @param {string} rawConfig - Raw configuration text
 * @returns {Promise<Object>} The response
 */
async function saveRawConfig(rawConfig) {
    return postJSON(URLS.API.SAVE_RAW_CONFIG, { raw_config: rawConfig });
}

/**
 * Save main configuration
 * @param {Object} config - Configuration object
 * @returns {Promise<Object>} The response
 */
async function saveMainConfig(config) {
    return postJSON(URLS.API.SAVE_MAIN_CONFIG, config);
}

/**
 * Save search engines configuration
 * @param {Object} config - Configuration object
 * @returns {Promise<Object>} The response
 */
async function saveSearchEnginesConfig(config) {
    return postJSON(URLS.API.SAVE_SEARCH_ENGINES_CONFIG, config);
}

/**
 * Save collections configuration
 * @param {Object} config - Configuration object
 * @returns {Promise<Object>} The response
 */
async function saveCollectionsConfig(config) {
    return postJSON(URLS.API.SAVE_COLLECTIONS_CONFIG, config);
}

/**
 * Save API keys configuration
 * @param {Object} config - Configuration object
 * @returns {Promise<Object>} The response
 */
async function saveApiKeysConfig(config) {
    return postJSON(URLS.API.SAVE_API_KEYS_CONFIG, config);
}

/**
 * Save LLM configuration
 * @param {Object} config - Configuration object
 * @returns {Promise<Object>} The response
 */
async function saveLlmConfig(config) {
    return postJSON(URLS.API.SAVE_LLM_CONFIG, config);
}

/**
 * Get markdown export for research
 * @param {number} researchId - The research ID
 * @returns {Promise<Object>} The markdown content
 */
async function getMarkdownExport(researchId) {
    return fetchWithErrorHandling(URLBuilder.markdownExport(researchId));
}

// Export for Node.js testing
if (typeof module !== 'undefined' && module.exports) {
    module.exports = {
        getCsrfToken,
        fetchWithErrorHandling,
        getApiUrl,
        postJSON,
        startResearch,
        getResearchStatus,
        getResearchDetails,
        getResearchLogs,
        getResearchHistory,
        getReport,
        getMarkdownExport,
        terminateResearch,
        deleteResearch,
        clearResearchHistory,
        openFileLocation,
        saveRawConfig,
        saveMainConfig,
        saveSearchEnginesConfig,
        saveCollectionsConfig,
        saveApiKeysConfig,
        saveLlmConfig
    };
}

// Make api available globally for browser usage
if (typeof window !== 'undefined') {
    window.api = {
        startResearch,
        getResearchStatus,
        getResearchDetails,
        getResearchLogs,
        getResearchHistory,
        getReport,
        getMarkdownExport,
        terminateResearch,
        deleteResearch,
        clearResearchHistory,
        openFileLocation,
        saveRawConfig,
        saveMainConfig,
        saveSearchEnginesConfig,
        saveCollectionsConfig,
        saveApiKeysConfig,
        saveLlmConfig,
        postJSON,
        getApiUrl,
        getCsrfToken,
        fetchWithErrorHandling
    };
}
