#![allow(unused_imports)]
use super::*;
use crate::config::extract_origin;
use std::collections::HashMap;

fn make_post(origin: Option<&str>) -> AuthRequest {
    let mut headers = HashMap::new();
    headers.insert("content-type".to_string(), "application/json".to_string());
    if let Some(o) = origin {
        headers.insert("origin".to_string(), o.to_string());
    }
    AuthRequest {
        method: HttpMethod::Post,
        path: "/sign-in/email".to_string(),
        headers,
        body: None,
        query: HashMap::new(),
        virtual_user_id: None,
    }
}

fn test_auth_config(trusted_origins: Vec<String>) -> Arc<AuthConfig> {
    Arc::new(
        AuthConfig::new("test-secret-key-that-is-at-least-32-characters-long")
            .base_url("http://localhost:3000")
            .trusted_origins(trusted_origins),
    )
}

#[tokio::test]
async fn test_csrf_allows_same_origin() {
    let mw = CsrfMiddleware::new(CsrfConfig::new(), test_auth_config(vec![]));
    let req = make_post(Some("http://localhost:3000"));
    assert!(mw.before_request(&req).await.unwrap().is_none());
}

#[tokio::test]
async fn test_csrf_blocks_cross_origin() {
    let mw = CsrfMiddleware::new(CsrfConfig::new(), test_auth_config(vec![]));
    let req = make_post(Some("http://evil.com"));
    let resp = mw.before_request(&req).await.unwrap();
    assert!(resp.is_some());
    let resp = resp.unwrap();
    assert_eq!(resp.status, 403);
    let body: serde_json::Value = serde_json::from_slice(&resp.body).unwrap();
    assert_eq!(body["code"], "CSRF_ERROR");
    assert_eq!(body["deliveredOrigin"], "http://evil.com");
    assert_eq!(body["expectedBaseOrigin"], "http://localhost:3000");
    assert_eq!(
        body["suggestedTrustedOriginsEnvLine"],
        "TRUSTED_ORIGINS=http://evil.com"
    );
}

#[tokio::test]
async fn test_csrf_allows_trusted_origin() {
    let mw = CsrfMiddleware::new(
        CsrfConfig::new(),
        test_auth_config(vec!["https://myapp.com".to_string()]),
    );
    let req = make_post(Some("https://myapp.com"));
    assert!(mw.before_request(&req).await.unwrap().is_none());
}

#[tokio::test]
async fn test_csrf_allows_glob_trusted_origin() {
    let mw = CsrfMiddleware::new(
        CsrfConfig::new(),
        test_auth_config(vec!["https://*.example.com".to_string()]),
    );
    let req = make_post(Some("https://app.example.com"));
    assert!(mw.before_request(&req).await.unwrap().is_none());
}

#[tokio::test]
async fn test_csrf_skips_get_requests() {
    let mw = CsrfMiddleware::new(CsrfConfig::new(), test_auth_config(vec![]));
    let req = AuthRequest {
        method: HttpMethod::Get,
        path: "/get-session".to_string(),
        headers: {
            let mut h = HashMap::new();
            h.insert("origin".to_string(), "http://evil.com".to_string());
            h
        },
        body: None,
        query: HashMap::new(),
        virtual_user_id: None,
    };
    assert!(mw.before_request(&req).await.unwrap().is_none());
}

#[tokio::test]
async fn test_csrf_allows_no_origin_header() {
    let mw = CsrfMiddleware::new(CsrfConfig::new(), test_auth_config(vec![]));
    let req = make_post(None);
    assert!(mw.before_request(&req).await.unwrap().is_none());
}

#[tokio::test]
async fn test_csrf_disabled() {
    let config = CsrfConfig::new().enabled(false);
    let mw = CsrfMiddleware::new(config, test_auth_config(vec![]));
    let req = make_post(Some("http://evil.com"));
    assert!(mw.before_request(&req).await.unwrap().is_none());
}

#[test]
fn test_extract_origin() {
    assert_eq!(
        extract_origin("https://example.com/path"),
        Some("https://example.com".to_string())
    );
    assert_eq!(
        extract_origin("http://localhost:3000"),
        Some("http://localhost:3000".to_string())
    );
    assert_eq!(extract_origin("not-a-url"), None);
}
