//! Comprehensive tests for agent service and execution logic
//!
//! These tests cover:
//! - Agent creation and configuration
//! - Agent execution flow and decision making
//! - History tracking and state management
//! - Usage tracking (tokens, cost)
//! - Error handling and recovery

use browsing::agent::views::{
    ActionResult, AgentHistory, AgentHistoryList, AgentSettings, AgentState,
};
use browsing::error::BrowsingError;
use std::collections::HashMap;

// ============================================================================
// Agent Creation Tests
// ============================================================================

#[test]
fn test_agent_task_validation() {
    let valid_tasks = vec![
        "Navigate to example.com and click the first link",
        "Search for 'rust programming' and extract the first result",
        "Fill out the contact form with test data",
        "Extract all product prices from the page",
        "Scroll to the bottom and load more content",
    ];

    for task in valid_tasks {
        assert!(!task.is_empty(), "Agent task should not be empty");
        assert!(task.len() <= 4096, "Agent task should be reasonable length");
    }
}

#[test]
fn test_agent_max_steps_validation() {
    let valid_max_steps = vec![1u32, 10, 50, 100, 500];

    for max_steps in valid_max_steps {
        assert!(max_steps > 0, "Max steps should be positive");
        assert!(max_steps <= 1000, "Max steps should be reasonable");
    }
}

#[test]
fn test_agent_default_state() {
    let _state = AgentState::default();

    // Default state should have no errors
    assert!(true, "AgentState created successfully");
}

#[test]
fn test_agent_settings_default() {
    let _settings = AgentSettings::default();

    // Default settings should be valid
    assert!(true, "AgentSettings created successfully");
}

// ============================================================================
// AgentSettings Tests
// ============================================================================

#[test]
fn test_agent_settings_system_message() {
    let system_messages = vec![
        "You are a helpful assistant.",
        "Navigate the web and complete tasks.",
        "Extract information from web pages efficiently.",
    ];

    for msg in system_messages {
        assert!(!msg.is_empty(), "System message should not be empty");
    }
}

#[test]
fn test_agent_settings_validation() {
    let settings = AgentSettings {
        override_system_message: Some("Custom system message".to_string()),
        ..Default::default()
    };

    assert!(settings.override_system_message.is_some());
}

// ============================================================================
// AgentHistory Tests
// ============================================================================

#[test]
fn test_agent_history_creation() {
    use browsing::browser::views::BrowserStateHistory;

    let history = AgentHistory {
        model_output: None,
        result: vec![ActionResult {
            extracted_content: Some("Test content".to_string()),
            ..Default::default()
        }],
        state: BrowserStateHistory {
            url: "https://example.com".to_string(),
            title: "Example".to_string(),
            tabs: vec![],
            interacted_element: vec![],
            screenshot_path: None,
        },
        metadata: None,
        state_message: None,
    };

    assert_eq!(history.result.len(), 1);
    assert!(history.result[0].extracted_content.is_some());
}

#[test]
fn test_agent_history_step_validation() {
    let valid_steps = vec![0u32, 1, 10, 100, 999];

    for step in valid_steps {
        assert!(step < u32::MAX, "Step should be valid");
    }
}

#[test]
fn test_agent_history_list_creation() {
    let history_list = AgentHistoryList {
        history: vec![],
    };

    assert!(history_list.history.is_empty());
}

#[test]
fn test_agent_history_list_with_entries() {
    use browsing::browser::views::BrowserStateHistory;

    let state = BrowserStateHistory {
        url: "https://example.com".to_string(),
        title: "Example".to_string(),
        tabs: vec![],
        interacted_element: vec![],
        screenshot_path: None,
    };

    let history_list = AgentHistoryList {
        history: vec![
            AgentHistory {
                model_output: None,
                result: vec![ActionResult::default()],
                state: state.clone(),
                metadata: None,
                state_message: None,
            },
            AgentHistory {
                model_output: None,
                result: vec![ActionResult::default()],
                state: state.clone(),
                metadata: None,
                state_message: None,
            },
        ],
    };

    assert_eq!(history_list.history.len(), 2);
}

// ============================================================================
// UsageTracker Tests
// ============================================================================

#[test]
fn test_usage_tracker_initial_state() {
    let prompt_tokens = 0u32;
    let completion_tokens = 0u32;
    let total_tokens = 0u32;

    assert_eq!(prompt_tokens, 0);
    assert_eq!(completion_tokens, 0);
    assert_eq!(total_tokens, 0);
}

#[test]
fn test_agent_with_custom_settings() {
    // Test custom agent settings
    use browsing::agent::views::VisionMode;

    let settings = AgentSettings {
        use_vision: VisionMode::Enabled(true),
        max_failures: 3,
        ..Default::default()
    };

    matches!(settings.use_vision, VisionMode::Enabled(_));
    assert_eq!(settings.max_failures, 3);
}

#[test]
fn test_cost_calculation() {
    let prompt_tokens = 1000u32;
    let completion_tokens = 500u32;
    let prompt_price_per_1k = 0.0001; // $0.0001 per 1K prompt tokens
    let completion_price_per_1k = 0.0002; // $0.0002 per 1K completion tokens

    let prompt_cost = (prompt_tokens as f64 / 1000.0) * prompt_price_per_1k;
    let completion_cost = (completion_tokens as f64 / 1000.0) * completion_price_per_1k;
    let total_cost = prompt_cost + completion_cost;

    assert!((prompt_cost - 0.0001).abs() < 0.00001);
    assert!((completion_cost - 0.0001).abs() < 0.00001);
    assert!((total_cost - 0.0002).abs() < 0.00001);
}

// ============================================================================
// ChatMessage Tests
// ============================================================================

#[test]
fn test_chat_message_role_validation() {
    let valid_roles = vec!["system", "user", "assistant", "tool"];

    for role in valid_roles {
        assert!(!role.is_empty(), "Role should not be empty");
        assert!(role.len() <= 20, "Role should be short");
    }
}

#[test]
fn test_chat_message_content_validation() {
    let valid_contents = vec![
        "You are a helpful assistant.",
        "Please navigate to the website and extract information.",
        "The task is complete.",
        "",
    ];

    for content in valid_contents {
        // Empty content is allowed for some message types
        assert!(
            content.len() <= 65536,
            "Content should be reasonable length"
        );
    }
}

// ============================================================================
// Agent State Management Tests
// ============================================================================

#[test]
fn test_agent_state_transitions() {
    let states = vec!["idle", "running", "paused", "completed", "error"];

    for state in states {
        assert!(!state.is_empty(), "State should not be empty");
    }
}

#[test]
fn test_agent_state_serialization() {
    let state = AgentState {
        agent_id: "test-agent-123".to_string(),
        n_steps: 5,
        ..Default::default()
    };

    assert_eq!(state.agent_id, "test-agent-123");
    assert_eq!(state.n_steps, 5);
}

#[test]
fn test_agent_state_with_selector_map() {
    use browsing::dom::views::DOMInteractedElement;

    let mut selector_map = HashMap::new();
    selector_map.insert(
        1u32,
        DOMInteractedElement {
            index: 1,
            backend_node_id: Some(123),
            tag: "button".to_string(),
            text: Some("Click".to_string()),
            attributes: HashMap::new(),
            selector: None,
            semantic_role: None,
            semantic_affordance: None,
            semantic_confidence: 0.0,
        },
    );

    assert_eq!(selector_map.len(), 1);
    assert!(selector_map.contains_key(&1));
}

// ============================================================================
// Agent Decision Making Tests
// ============================================================================

#[test]
fn test_action_model_validation() {
    let valid_actions = vec![
        "search",
        "navigate",
        "click",
        "input",
        "scroll",
        "extract_content",
        "create_tab",
        "switch_tab",
    ];

    for action in valid_actions {
        assert!(!action.is_empty(), "Action should not be empty");
    }
}

#[test]
fn test_action_parameters_validation() {
    let test_cases = vec![
        ("url", "https://example.com"),
        ("query", "search term"),
        ("index", "1"),
        ("text", "input text"),
        ("pages", "1.5"),
    ];

    for (key, value) in test_cases {
        assert!(!key.is_empty(), "Parameter key should not be empty");
        assert!(!value.is_empty(), "Parameter value should not be empty");
    }
}

#[test]
fn test_action_result_validation() {
    let result = ActionResult {
        extracted_content: Some("Content".to_string()),
        long_term_memory: Some("Memory".to_string()),
        is_done: Some(true),
        ..Default::default()
    };

    assert_eq!(result.extracted_content, Some("Content".to_string()));
    assert_eq!(result.long_term_memory, Some("Memory".to_string()));
    assert_eq!(result.is_done, Some(true));
}

// ============================================================================
// Error Handling Tests
// ============================================================================

#[test]
fn test_agent_error_max_steps_exceeded() {
    let max_steps = 10u32;
    let current_step = 11u32;

    let exceeded = current_step > max_steps;
    assert!(exceeded, "Should detect max steps exceeded");
}

#[test]
fn test_agent_error_invalid_action() {
    let invalid_action = "invalid_action";
    let valid_actions = vec!["search", "navigate", "click"];

    let is_valid = valid_actions.contains(&invalid_action);
    assert!(!is_valid, "Should detect invalid action");
}

#[test]
fn test_agent_error_missing_parameter() {
    let required_params = vec!["url", "query"];
    let provided_params = vec!["url"];

    let has_all_required = required_params.iter().all(|p| provided_params.contains(p));

    assert!(!has_all_required, "Should detect missing parameter");
}

#[test]
fn test_agent_recovery_from_failure() {
    let retry_attempts = vec![1u32, 2, 3];

    for attempt in retry_attempts {
        assert!(attempt <= 3, "Should limit retry attempts");
    }
}

// ============================================================================
// JSON Extraction Tests
// ============================================================================

#[test]
fn test_json_extraction_valid() {
    let valid_json = r#"{"action": "click", "index": 1}"#;
    let parsed: Result<serde_json::Value, _> = serde_json::from_str(valid_json);

    assert!(parsed.is_ok(), "Should parse valid JSON");
}

#[test]
fn test_json_extraction_invalid() {
    let invalid_json = r#"{action: "click", index: 1}"#;
    let parsed: Result<serde_json::Value, _> = serde_json::from_str(invalid_json);

    assert!(parsed.is_err(), "Should fail to parse invalid JSON");
}

#[test]
fn test_json_extraction_malformed() {
    let malformed_json = r#"{"action": "click", "index": }"#;
    let parsed: Result<serde_json::Value, _> = serde_json::from_str(malformed_json);

    assert!(parsed.is_err(), "Should fail to parse malformed JSON");
}

#[test]
fn test_json_repair_attempt() {
    let broken_json = r#"{action: click, index: 1}"#;
    let repaired = broken_json
        .replace(r#"{"#, r#"{"action":"#)
        .replace(r#":"click"#, r#"","action":"click"#)
        .replace(r#"index: "#, r#""index": "#);

    // The repair logic would fix this
    assert!(!repaired.is_empty());
}

// ============================================================================
// Integration Test Markers
// ============================================================================

#[test]
fn test_agent_execution_flow() {
    // Test agent execution flow structure and validation
    // Verify agent can handle valid task descriptions
    let tasks = vec![
        "Navigate to example.com",
        "Find the search button",
        "Click submit",
    ];

    for task in tasks {
        assert!(!task.is_empty(), "Agent task should not be empty");
        assert!(task.len() > 5, "Agent task should be descriptive");
    }

    // Verify action result structure
    let action_result = ActionResult::default();
    assert!(action_result.extracted_content.is_none());
    assert!(action_result.error.is_none());
}

#[test]
fn test_agent_with_multiple_steps() {
    // Test multi-step agent task tracking
    use browsing::agent::views::{AgentHistory, StepMetadata};
    use browsing::browser::views::BrowserStateHistory;

    let history_list = AgentHistoryList {
        history: vec![
            AgentHistory {
                model_output: None,
                result: vec![],
                state: BrowserStateHistory {
                    url: "https://example.com".to_string(),
                    title: "Example".to_string(),
                    tabs: vec![],
                    interacted_element: vec![],
                    screenshot_path: None,
                },
                metadata: Some(StepMetadata {
                    step_start_time: chrono::Utc::now().timestamp() as f64,
                    step_end_time: chrono::Utc::now().timestamp() as f64,
                    step_number: 1,
                }),
                state_message: Some("Step 1 completed".to_string()),
            },
            AgentHistory {
                model_output: None,
                result: vec![],
                state: BrowserStateHistory {
                    url: "https://example.com".to_string(),
                    title: "Example".to_string(),
                    tabs: vec![],
                    interacted_element: vec![],
                    screenshot_path: None,
                },
                metadata: Some(StepMetadata {
                    step_start_time: chrono::Utc::now().timestamp() as f64,
                    step_end_time: chrono::Utc::now().timestamp() as f64,
                    step_number: 2,
                }),
                state_message: Some("Step 2 completed".to_string()),
            },
        ],
    };

    // Verify multiple steps are tracked
    assert_eq!(history_list.history.len(), 2);

    // Verify all steps have valid metadata
    for history in &history_list.history {
        assert!(history.metadata.is_some());
    }
}

#[test]
fn test_agent_error_recovery() {
    // Test agent error handling structure
    use browsing::agent::views::{AgentHistory, StepMetadata};
    use browsing::browser::views::BrowserStateHistory;

    let error_messages = vec![
        "Navigation failed".to_string(),
        "Timeout occurred".to_string(),
        "Invalid action".to_string(),
    ];

    for error_msg in error_messages {
        assert!(!error_msg.is_empty());

        // Create history with error state message
        let history = AgentHistory {
            model_output: None,
            result: vec![],
            state: BrowserStateHistory {
                url: "https://example.com".to_string(),
                title: "Example".to_string(),
                tabs: vec![],
                interacted_element: vec![],
                screenshot_path: None,
            },
            metadata: None,
            state_message: Some(error_msg),
        };

        assert!(history.state_message.is_some());
    }
}

#[test]
fn test_agent_state_snapshots() {
    // Test state snapshot creation and serialization
    use browsing::agent::views::{AgentHistory, AgentOutput};
    use browsing::browser::views::BrowserStateHistory;
    use serde_json::json;

    let history = AgentHistory {
        model_output: Some(AgentOutput {
            action: vec![json!({
                "action_type": "navigate",
                "params": {"url": "https://example.com"}
            })],
            thinking: Some("Navigate to example.com".to_string()),
            evaluation_previous_goal: None,
            memory: None,
            next_goal: None,
        }),
        result: vec![ActionResult {
            is_done: Some(false),
            success: Some(true),
            judgement: None,
            error: None,
            attachments: None,
            images: None,
            long_term_memory: None,
            extracted_content: Some("Navigation successful".to_string()),
            include_extracted_content_only_once: false,
            metadata: None,
        }],
        state: BrowserStateHistory {
            url: "https://example.com".to_string(),
            title: "Example".to_string(),
            tabs: vec![],
            interacted_element: vec![],
            screenshot_path: None,
        },
        metadata: None,
        state_message: None,
    };

    // Verify snapshot structure
    assert!(history.model_output.is_some());
    assert!(!history.result.is_empty());
    assert_eq!(history.state.url, "https://example.com");
}
