// [DEF:api_module:Module]
// @SEMANTICS: api, client, fetch, rest
// @PURPOSE: Handles all communication with the backend API.
// @LAYER: Infra-API

import { addToast } from './toasts.js';
import { PUBLIC_WS_URL } from '$env/static/public';

const API_BASE_URL = '/api';

// [DEF:getWsUrl:Function]
// @PURPOSE: Returns the WebSocket URL for a specific task, with fallback logic.
// @PRE: taskId is provided.
// @POST: Returns valid WebSocket URL string.
// @PARAM:   taskId (string) - The ID of the task.
// @RETURN:  string - The WebSocket URL.
export const getWsUrl = (taskId) => {
    let baseUrl = PUBLIC_WS_URL;
    if (!baseUrl) {
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        // Use the current host and port to allow Vite proxy to handle the connection
        baseUrl = `${protocol}//${window.location.host}`;
    }
    return `${baseUrl}/ws/logs/${taskId}`;
};
// [/DEF:getWsUrl:Function]

// [DEF:getAuthHeaders:Function]
// @PURPOSE: Returns headers with Authorization if token exists.
function getAuthHeaders() {
    const headers = {
        'Content-Type': 'application/json',
    };
    if (typeof window !== 'undefined') {
        const token = localStorage.getItem('auth_token');
        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
        }
    }
    return headers;
}
// [/DEF:getAuthHeaders:Function]

// [DEF:fetchApi:Function]
// @PURPOSE: Generic GET request wrapper.
// @PRE: endpoint string is provided.
// @POST: Returns Promise resolving to JSON data or throws on error.
// @PARAM: endpoint (string) - API endpoint.
// @RETURN: Promise<any> - JSON response.
async function fetchApi(endpoint) {
    try {
        console.log(`[api.fetchApi][Action] Fetching from context={{'endpoint': '${endpoint}'}}`);
        const response = await fetch(`${API_BASE_URL}${endpoint}`, {
            headers: getAuthHeaders()
        });
        console.log(`[api.fetchApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            const message = errorData.detail
                ? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
                : `API request failed with status ${response.status}`;
            throw new Error(message);
        }
        if (response.status === 204) return null;
        return await response.json();
    } catch (error) {
        console.error(`[api.fetchApi][Coherence:Failed] Error fetching from ${endpoint}:`, error);
        addToast(error.message, 'error');
        throw error;
    }
}
// [/DEF:fetchApi:Function]

// [DEF:postApi:Function]
// @PURPOSE: Generic POST request wrapper.
// @PRE: endpoint and body are provided.
// @POST: Returns Promise resolving to JSON data or throws on error.
// @PARAM: endpoint (string) - API endpoint.
// @PARAM: body (object) - Request payload.
// @RETURN: Promise<any> - JSON response.
async function postApi(endpoint, body) {
    try {
        console.log(`[api.postApi][Action] Posting to context={{'endpoint': '${endpoint}'}}`);
        const response = await fetch(`${API_BASE_URL}${endpoint}`, {
            method: 'POST',
            headers: getAuthHeaders(),
            body: JSON.stringify(body),
        });
        console.log(`[api.postApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            const message = errorData.detail
                ? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
                : `API request failed with status ${response.status}`;
            throw new Error(message);
        }
        if (response.status === 204) return null;
        return await response.json();
    } catch (error) {
        console.error(`[api.postApi][Coherence:Failed] Error posting to ${endpoint}:`, error);
        addToast(error.message, 'error');
        throw error;
    }
}
// [/DEF:postApi:Function]

// [DEF:requestApi:Function]
// @PURPOSE: Generic request wrapper.
// @PRE: endpoint and method are provided.
// @POST: Returns Promise resolving to JSON data or throws on error.
async function requestApi(endpoint, method = 'GET', body = null) {
    try {
        console.log(`[api.requestApi][Action] ${method} to context={{'endpoint': '${endpoint}'}}`);
        const options = {
            method,
            headers: getAuthHeaders(),
        };
        if (body) {
            options.body = JSON.stringify(body);
        }
        const response = await fetch(`${API_BASE_URL}${endpoint}`, options);
        console.log(`[api.requestApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            const message = errorData.detail
                ? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
                : `API request failed with status ${response.status}`;
            console.error(`[api.requestApi][Action] Request failed context={{'status': ${response.status}, 'message': '${message}'}}`);
            throw new Error(message);
        }
        if (response.status === 204) {
            console.log('[api.requestApi][Action] 204 No Content received');
            return null;
        }
        return await response.json();
    } catch (error) {
        console.error(`[api.requestApi][Coherence:Failed] Error ${method} to ${endpoint}:`, error);
        addToast(error.message, 'error');
        throw error;
    }
}
// [/DEF:requestApi:Function]

// [DEF:api:Data]
// @PURPOSE: API client object with specific methods.
export const api = {
    fetchApi,
    postApi,
    requestApi,
    getPlugins: () => fetchApi('/plugins'),
    getTasks: () => fetchApi('/tasks'),
    getTask: (taskId) => fetchApi(`/tasks/${taskId}`),
    createTask: (pluginId, params) => postApi('/tasks', { plugin_id: pluginId, params }),
    
    // Settings
    getSettings: () => fetchApi('/settings'),
    updateGlobalSettings: (settings) => requestApi('/settings/global', 'PATCH', settings),
    getEnvironments: () => fetchApi('/settings/environments'),
    addEnvironment: (env) => postApi('/settings/environments', env),
    updateEnvironment: (id, env) => requestApi(`/settings/environments/${id}`, 'PUT', env),
    deleteEnvironment: (id) => requestApi(`/settings/environments/${id}`, 'DELETE'),
    testEnvironmentConnection: (id) => postApi(`/settings/environments/${id}/test`, {}),
    updateEnvironmentSchedule: (id, schedule) => requestApi(`/environments/${id}/schedule`, 'PUT', schedule),
    getStorageSettings: () => fetchApi('/settings/storage'),
    updateStorageSettings: (storage) => requestApi('/settings/storage', 'PUT', storage),
    getEnvironmentsList: () => fetchApi('/environments'),
};
// [/DEF:api:Data]

// [/DEF:api_module:Module]

// Export individual functions for easier use in components
export { requestApi };
export const getPlugins = api.getPlugins;
export const getTasks = api.getTasks;
export const getTask = api.getTask;
export const createTask = api.createTask;
export const getSettings = api.getSettings;
export const updateGlobalSettings = api.updateGlobalSettings;
export const getEnvironments = api.getEnvironments;
export const addEnvironment = api.addEnvironment;
export const updateEnvironment = api.updateEnvironment;
export const deleteEnvironment = api.deleteEnvironment;
export const testEnvironmentConnection = api.testEnvironmentConnection;
export const updateEnvironmentSchedule = api.updateEnvironmentSchedule;
export const getEnvironmentsList = api.getEnvironmentsList;
export const getStorageSettings = api.getStorageSettings;
export const updateStorageSettings = api.updateStorageSettings;
