//! Runtime configuration for the Syntaxis Dashboard
//!
//! This module handles loading API configuration at runtime from the browser environment.
//! The configuration is injected into `window.SYNTAXIS_CONFIG` by `index.html`.
//!
//! # Configuration Sources
//!
//! In order of precedence:
//! 1. URL query parameter: `?apiUrl=http://custom-api:3000`
//! 2. `window.SYNTAXIS_CONFIG.apiUrl` (set by index.html)
//! 3. Default: `window.location.origin` (same-origin, current domain)
//!
//! # Example
//!
//! ```
//! // Default behavior (auto-detect from current domain)
//! let url = get_api_base_url();
//! // Result: "http://localhost:3000" (if served on localhost:3000)
//!
//! // Override via URL parameter
//! // Visit: http://localhost:8080?apiUrl=http://remote-api:3000
//! let url = get_api_base_url();
//! // Result: "http://remote-api:3000"
//! ```

#![forbid(unsafe_code)]

use js_sys::Reflect;
use wasm_bindgen::JsValue;
use web_sys::window;

/// Get the API base URL from browser configuration
///
/// Returns the configured API URL with priority:
/// 1. URL parameter `?apiUrl=...`
/// 2. `window.SYNTAXIS_CONFIG.apiUrl`
/// 3. `window.location.origin` (same-origin default)
///
/// # Panics
///
/// Panics if `window` is not available (shouldn't happen in browser context)
#[must_use]
pub fn get_api_base_url() -> String {
    let window = window().expect("window should be available");

    // Try to get apiUrl from window.SYNTAXIS_CONFIG
    let config_url = get_config_api_url(&window);
    if let Some(url) = config_url {
        return url;
    }

    // Fall back to window.location.origin
    window
        .location()
        .origin()
        .unwrap_or_else(|_| "http://localhost:3000".to_string())
}

/// Get the API path prefix from configuration (default: /api)
#[must_use]
pub fn get_api_path() -> String {
    let window = match window() {
        Some(w) => w,
        None => return "/api".to_string(),
    };

    get_config_api_path(&window).unwrap_or_else(|| "/api".to_string())
}

/// Get the full API URL including path prefix
///
/// Example: `http://localhost:3000/api`
#[must_use]
pub fn get_api_url() -> String {
    format!("{}{}", get_api_base_url(), get_api_path())
}

fn get_config_api_url(window: &web_sys::Window) -> Option<String> {
    // First, try URL parameter (?apiUrl=...)
    if let Some(url) = get_url_param_api_url(window) {
        return Some(url);
    }

    // Then try window.SYNTAXIS_CONFIG.apiUrl
    let config = Reflect::get(window, &JsValue::from_str("SYNTAXIS_CONFIG")).ok()?;
    Reflect::get(&config, &JsValue::from_str("apiUrl"))
        .ok()?
        .as_string()
}

fn get_config_api_path(window: &web_sys::Window) -> Option<String> {
    let config = Reflect::get(window, &JsValue::from_str("SYNTAXIS_CONFIG")).ok()?;
    Reflect::get(&config, &JsValue::from_str("apiPath"))
        .ok()?
        .as_string()
}

fn get_url_param_api_url(window: &web_sys::Window) -> Option<String> {
    let location = window.location();
    let search = location.search().ok()?;

    // Parse URL parameters
    let params = web_sys::UrlSearchParams::new_with_str(&search).ok()?;
    params.get("apiUrl")
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_get_api_path() {
        // This test runs in a test environment without a browser
        // The actual function requires window, so we just verify the default
        let path = "/api".to_string();
        assert_eq!(path, "/api");
    }

    #[test]
    fn test_api_url_construction() {
        let base = "http://localhost:3000".to_string();
        let path = "/api".to_string();
        let full_url = format!("{}{}", base, path);
        assert_eq!(full_url, "http://localhost:3000/api");
    }
}
