#[cfg(all(test, feature = "server"))]
mod tests {
    use crate::modes::server::auth::{Claims, check_permission, required_permission, validate_jwt};
    use crate::modes::server::common::check_auth;
    use axum::http::{HeaderMap, HeaderValue, Method};
    use jsonwebtoken::{EncodingKey, Header, encode};

    fn make_jwt(claims: &serde_json::Value, secret: &str) -> String {
        let header = Header::new(jsonwebtoken::Algorithm::HS256);
        encode(
            &header,
            claims,
            &EncodingKey::from_secret(secret.as_bytes()),
        )
        .unwrap()
    }

    fn make_basic_auth(username: &str, password: &str) -> String {
        use base64::Engine;
        let credentials = format!("{username}:{password}");
        let encoded = base64::engine::general_purpose::STANDARD.encode(&credentials);
        format!("Basic {encoded}")
    }

    // --- Password auth tests (Basic auth) ---

    #[test]
    fn test_auth_with_no_password_required() {
        let headers = HeaderMap::new();
        assert!(check_auth(&headers, &None, &None, &None));
    }

    #[test]
    fn test_auth_with_basic_auth_default_username() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "authorization",
            HeaderValue::from_str(&make_basic_auth("keep", "secret123")).unwrap(),
        );
        let password = Some("secret123".to_string());
        assert!(check_auth(&headers, &None, &password, &None));
    }

    #[test]
    fn test_auth_with_basic_auth_custom_username() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "authorization",
            HeaderValue::from_str(&make_basic_auth("admin", "secret123")).unwrap(),
        );
        let username = Some("admin".to_string());
        let password = Some("secret123".to_string());
        assert!(check_auth(&headers, &username, &password, &None));
    }

    #[test]
    fn test_auth_with_basic_auth_wrong_password() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "authorization",
            HeaderValue::from_str(&make_basic_auth("keep", "wrongpass")).unwrap(),
        );
        let password = Some("secret123".to_string());
        assert!(!check_auth(&headers, &None, &password, &None));
    }

    #[test]
    fn test_auth_with_basic_auth_wrong_username() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "authorization",
            HeaderValue::from_str(&make_basic_auth("wrong", "secret123")).unwrap(),
        );
        let username = Some("admin".to_string());
        let password = Some("secret123".to_string());
        assert!(!check_auth(&headers, &username, &password, &None));
    }

    #[test]
    fn test_auth_with_basic_auth_wrong_password_custom_username() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "authorization",
            HeaderValue::from_str(&make_basic_auth("admin", "wrongpass")).unwrap(),
        );
        let username = Some("admin".to_string());
        let password = Some("secret123".to_string());
        assert!(!check_auth(&headers, &username, &password, &None));
    }

    #[test]
    fn test_auth_bearer_token_ignored_for_password_auth() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "authorization",
            HeaderValue::from_static("Bearer secret123"),
        );
        let password = Some("secret123".to_string());
        // Bearer tokens are not checked for password auth — only Basic auth is valid
        assert!(!check_auth(&headers, &None, &password, &None));
    }

    #[test]
    fn test_auth_with_missing_auth_header() {
        let headers = HeaderMap::new();
        let password = Some("secret123".to_string());
        assert!(!check_auth(&headers, &None, &password, &None));
    }

    #[test]
    fn test_auth_with_malformed_auth_header() {
        let mut headers = HeaderMap::new();
        headers.insert("authorization", HeaderValue::from_static("Invalid header"));
        let password = Some("secret123".to_string());
        assert!(!check_auth(&headers, &None, &password, &None));
    }

    // --- JWT validation tests ---

    #[test]
    fn test_validate_jwt_valid_token() {
        let secret = "test-secret";
        let claims = serde_json::json!({
            "sub": "test-client",
            "exp": 9999999999usize,
            "read": true,
            "write": true,
            "delete": false
        });
        let token = make_jwt(&claims, secret);

        let result = validate_jwt(&token, secret);
        assert!(result.is_ok());
        let claims = result.unwrap();
        assert_eq!(claims.sub, "test-client");
        assert!(claims.read);
        assert!(claims.write);
        assert!(!claims.delete);
    }

    #[test]
    fn test_validate_jwt_expired() {
        let secret = "test-secret";
        let claims = serde_json::json!({
            "sub": "test-client",
            "exp": 1000000000usize,
            "read": true
        });
        let token = make_jwt(&claims, secret);

        let result = validate_jwt(&token, secret);
        assert!(result.is_err());
    }

    #[test]
    fn test_validate_jwt_wrong_secret() {
        let claims = serde_json::json!({
            "sub": "test-client",
            "exp": 9999999999usize,
            "read": true
        });
        let token = make_jwt(&claims, "correct-secret");

        let result = validate_jwt(&token, "wrong-secret");
        assert!(result.is_err());
    }

    #[test]
    fn test_validate_jwt_malformed() {
        let result = validate_jwt("not.a.jwt", "secret");
        assert!(result.is_err());
    }

    #[test]
    fn test_validate_jwt_missing_permissions_default_false() {
        let secret = "test-secret";
        let claims = serde_json::json!({
            "sub": "test-client",
            "exp": 9999999999usize
        });
        let token = make_jwt(&claims, secret);

        let claims = validate_jwt(&token, secret).unwrap();
        assert!(!claims.read);
        assert!(!claims.write);
        assert!(!claims.delete);
    }

    // --- Permission tests ---

    #[test]
    fn test_required_permission_mapping() {
        assert_eq!(required_permission(&Method::GET), "read");
        assert_eq!(required_permission(&Method::HEAD), "read");
        assert_eq!(required_permission(&Method::POST), "write");
        assert_eq!(required_permission(&Method::PUT), "write");
        assert_eq!(required_permission(&Method::PATCH), "write");
        assert_eq!(required_permission(&Method::DELETE), "delete");
    }

    #[test]
    fn test_check_permission_granted() {
        let claims = Claims {
            sub: "test".to_string(),
            exp: 9999999999,
            read: true,
            write: false,
            delete: true,
        };

        assert!(check_permission(&claims, "read"));
        assert!(!check_permission(&claims, "write"));
        assert!(check_permission(&claims, "delete"));
    }

    #[test]
    fn test_check_permission_unknown_denied() {
        let claims = Claims {
            sub: "test".to_string(),
            exp: 9999999999,
            read: true,
            write: true,
            delete: true,
        };

        assert!(!check_permission(&claims, "unknown"));
    }

    // --- End-to-end permission scenarios ---

    #[test]
    fn test_read_only_token_scenarios() {
        let secret = "test-secret";
        let claims = serde_json::json!({
            "sub": "readonly-client",
            "exp": 9999999999usize,
            "read": true,
            "write": false,
            "delete": false
        });
        let token = make_jwt(&claims, secret);
        let claims = validate_jwt(&token, secret).unwrap();

        // GET (read) should be allowed
        assert!(check_permission(&claims, required_permission(&Method::GET)));
        // POST (write) should be denied
        assert!(!check_permission(
            &claims,
            required_permission(&Method::POST)
        ));
        // DELETE should be denied
        assert!(!check_permission(
            &claims,
            required_permission(&Method::DELETE)
        ));
    }

    #[test]
    fn test_full_access_token_scenarios() {
        let secret = "test-secret";
        let claims = serde_json::json!({
            "sub": "admin",
            "exp": 9999999999usize,
            "read": true,
            "write": true,
            "delete": true
        });
        let token = make_jwt(&claims, secret);
        let claims = validate_jwt(&token, secret).unwrap();

        assert!(check_permission(&claims, required_permission(&Method::GET)));
        assert!(check_permission(
            &claims,
            required_permission(&Method::POST)
        ));
        assert!(check_permission(&claims, required_permission(&Method::PUT)));
        assert!(check_permission(
            &claims,
            required_permission(&Method::DELETE)
        ));
    }

    #[test]
    fn test_write_only_token_scenarios() {
        let secret = "test-secret";
        let claims = serde_json::json!({
            "sub": "writer",
            "exp": 9999999999usize,
            "read": false,
            "write": true,
            "delete": false
        });
        let token = make_jwt(&claims, secret);
        let claims = validate_jwt(&token, secret).unwrap();

        assert!(!check_permission(
            &claims,
            required_permission(&Method::GET)
        ));
        assert!(check_permission(
            &claims,
            required_permission(&Method::POST)
        ));
        assert!(!check_permission(
            &claims,
            required_permission(&Method::DELETE)
        ));
    }
}
