// Tests for mecha10_cli::sim::selector

use mecha10_cli::sim::selector::*;

use crate::sim::profile::TaskNode;
use std::collections::HashMap;

fn create_test_environment(
    id: &str,
    tags: Vec<&str>,
    required_sensors: Vec<&str>,
    platforms: Vec<&str>,
    task_nodes: Vec<&str>,
    difficulty: &str,
) -> Environment {
    Environment {
        id: id.to_string(),
        path: format!("{}.tscn", id),
        name: id.to_string(),
        description: id.to_string(),
        tags: tags.iter().map(|s| s.to_string()).collect(),
        required_sensors: required_sensors.iter().map(|s| s.to_string()).collect(),
        optional_sensors: vec![],
        robot_platforms: platforms.iter().map(|s| s.to_string()).collect(),
        task_nodes: task_nodes.iter().map(|s| s.to_string()).collect(),
        difficulty: difficulty.to_string(),
        dimensions: vec![],
        features: Default::default(),
        curriculum_stage: 0,
        estimated_duration_s: 0,
        reward_config: HashMap::new(),
    }
}

fn create_test_profile(platform: &str, sensors: Vec<&str>, task_nodes: Vec<(&str, Vec<&str>)>) -> RobotProfile {
    RobotProfile {
        platform: platform.to_string(),
        sensors: sensors.iter().map(|s| s.to_string()).collect(),
        sensor_configs: vec![],
        task_nodes: task_nodes
            .iter()
            .map(|(name, tags)| TaskNode {
                name: name.to_string(),
                description: String::new(),
                tags: tags.iter().map(|t| t.to_string()).collect(),
            })
            .collect(),
        capabilities: vec![],
        difficulty_preference: "medium".to_string(),
    }
}

#[test]
fn test_score_task_node_match() {
    let env = create_test_environment(
        "cafe_delivery",
        vec!["delivery", "navigation"],
        vec!["lidar"],
        vec!["rover"],
        vec!["task_planner_node"],
        "medium",
    );

    let profile = create_test_profile("rover", vec!["lidar"], vec![("task_planner_node", vec!["delivery"])]);

    let catalog = EnvironmentCatalog {
        version: "0.1.0".to_string(),
        environments: vec![env],
        tags: HashMap::new(),
        difficulty_levels: HashMap::new(),
    };

    let selector = EnvironmentSelector::with_catalog(catalog);
    let matches = selector.select_environments(&profile, 1).unwrap();

    assert!(!matches.is_empty());
    // Task node match (+20) + Tag match (+10) + Sensors (+5) + Platform (+3) + Difficulty (+2)
    assert!(matches[0].score >= 40);
}

#[test]
fn test_score_missing_sensors() {
    let env = create_test_environment(
        "test_env",
        vec![],
        vec!["lidar", "camera"], // Requires camera
        vec!["rover"],
        vec![],
        "easy",
    );

    let profile = create_test_profile(
        "rover",
        vec!["lidar"], // Only has lidar, missing camera
        vec![],
    );

    let catalog = EnvironmentCatalog {
        version: "0.1.0".to_string(),
        environments: vec![env],
        tags: HashMap::new(),
        difficulty_levels: HashMap::new(),
    };

    let selector = EnvironmentSelector::with_catalog(catalog);
    let matches = selector.select_environments(&profile, 10).unwrap();

    // Should be filtered out due to negative score
    assert!(matches.is_empty() || matches[0].score < 0);
}

#[test]
fn test_ranking_by_score() {
    let env1 = create_test_environment(
        "high_match",
        vec!["delivery"],
        vec!["lidar"],
        vec!["rover"],
        vec!["task_planner_node"],
        "medium",
    );

    let env2 = create_test_environment(
        "low_match",
        vec!["navigation"],
        vec!["lidar"],
        vec!["rover"],
        vec![],
        "easy",
    );

    let profile = create_test_profile("rover", vec!["lidar"], vec![("task_planner_node", vec!["delivery"])]);

    let catalog = EnvironmentCatalog {
        version: "0.1.0".to_string(),
        environments: vec![env1, env2],
        tags: HashMap::new(),
        difficulty_levels: HashMap::new(),
    };

    let selector = EnvironmentSelector::with_catalog(catalog);
    let matches = selector.select_environments(&profile, 2).unwrap();

    assert_eq!(matches.len(), 2);
    // First should be high_match (task node + tag matches)
    assert_eq!(matches[0].environment.id, "high_match");
    assert!(matches[0].score > matches[1].score);
}
