//! SPA router detection logic.

use eoka::{Page, Result};
use serde::Deserialize;
use std::collections::HashMap;

use super::{RouterType, SpaRouterInfo};

/// Raw detection result from JavaScript.
#[derive(Debug, Deserialize)]
struct JsDetectionResult {
    router_type: String,
    path: String,
    query: HashMap<String, String>,
    hash: String,
    can_navigate: bool,
    details: Option<String>,
}

/// JavaScript code for detecting SPA routers.
const DETECT_JS: &str = include_str!("../js/spa_detect.js");

/// Detect the SPA router type and current route state.
pub async fn detect_router(page: &Page) -> Result<SpaRouterInfo> {
    let json: String = page.evaluate(DETECT_JS).await?;
    let raw: JsDetectionResult = serde_json::from_str(&json)
        .map_err(|e| eoka::Error::CdpSimple(format!("Failed to parse router detection: {}", e)))?;

    let router_type = match raw.router_type.as_str() {
        "react-router" => RouterType::ReactRouter,
        "nextjs" => RouterType::NextJs,
        "vue-router" => RouterType::VueRouter,
        "angular-router" => RouterType::AngularRouter,
        "history-api" => RouterType::HistoryApi,
        _ => RouterType::Unknown,
    };

    Ok(SpaRouterInfo {
        router_type,
        current_path: raw.path,
        query_params: raw.query,
        hash: raw.hash,
        can_navigate: raw.can_navigate,
        details: raw.details,
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_router_type_display() {
        assert_eq!(RouterType::ReactRouter.to_string(), "React Router");
        assert_eq!(RouterType::NextJs.to_string(), "Next.js");
        assert_eq!(RouterType::VueRouter.to_string(), "Vue Router");
        assert_eq!(RouterType::AngularRouter.to_string(), "Angular Router");
        assert_eq!(RouterType::HistoryApi.to_string(), "History API");
        assert_eq!(RouterType::Unknown.to_string(), "Unknown");
    }
}
