//! Expanded test suite for comprehensive coverage

use crate::checklist::{Checklist, ChecklistItem, ChecklistManager};
use crate::config::ProjectConfig;
use crate::context::ProjectContext;
use crate::phase::{PhaseManager, ProjectPhase};
use crate::tools::{ToolConfig, ToolManager};
use crate::types::{ProjectMode, ProjectType, ToolMode};
use std::path::PathBuf;

// ============================================
// Phase Manager Tests
// ============================================

#[test]
fn test_phase_manager_all_transitions() {
    let mut manager = PhaseManager::new(ProjectPhase::Creation);

    // Creation → Devel
    assert!(manager.can_transition(ProjectPhase::Devel));
    manager.transition_to(ProjectPhase::Devel, true).unwrap();
    assert_eq!(manager.current_phase(), ProjectPhase::Devel);

    // Devel → Review
    assert!(manager.can_transition(ProjectPhase::Review));
    manager.transition_to(ProjectPhase::Review, false).unwrap();
    assert_eq!(manager.current_phase(), ProjectPhase::Review);

    // Review → Publish
    assert!(manager.can_transition(ProjectPhase::Publish));
    manager.transition_to(ProjectPhase::Publish, true).unwrap();
    assert_eq!(manager.current_phase(), ProjectPhase::Publish);

    // Archive is not next logical phase from Publish
    assert!(!manager.can_transition(ProjectPhase::Archive));
}

#[test]
fn test_phase_manager_multiple_paths() {
    // Creation can go to Devel, MVP, or Prototype
    let phases = ProjectPhase::Creation.next_phases();
    assert!(phases.contains(&ProjectPhase::Devel));
    assert!(phases.contains(&ProjectPhase::Mvp));
    assert!(phases.contains(&ProjectPhase::Prototype));
}

#[test]
fn test_phase_manager_time_tracking() {
    let mut manager = PhaseManager::new(ProjectPhase::Creation);
    // Transition to another phase first to have history
    manager.transition_to(ProjectPhase::Devel, false).ok();
    // Now time in current phase should be set
    let time = manager.time_in_current_phase();
    assert!(time.is_some());
}

// ============================================
// Tool Manager Tests
// ============================================

#[test]
fn test_tool_manager_enable_disable() {
    let mut manager = ToolManager::builtin();

    // Enable tracking tool
    assert!(manager.enable_tool("tracking").is_ok());
    assert!(manager.get_tool("tracking").unwrap().enabled);

    // Disable it
    assert!(manager.disable_tool("tracking").is_ok());
    assert!(!manager.get_tool("tracking").unwrap().enabled);
}

#[test]
fn test_tool_manager_creation() {
    let mut manager = ToolManager::builtin();

    // Enable a tool
    assert!(manager.enable_tool("tracking").is_ok());

    // Check it's enabled
    let tool = manager.get_tool("tracking").unwrap();
    assert!(tool.enabled);
}

#[test]
fn test_tool_config_with_builder() {
    let tool = ToolConfig::new("docs")
        .enable()
        .with_phases(vec![ProjectPhase::Devel, ProjectPhase::Review])
        .with_mode(ToolMode::Automatic);

    assert!(tool.enabled);
    assert_eq!(tool.mode, ToolMode::Automatic);
    assert_eq!(tool.phases.len(), 2);
}

// ============================================
// Checklist Manager Tests
// ============================================

#[test]
fn test_checklist_completion_tracking() {
    let mut checklist = Checklist::new(ProjectPhase::Devel);

    // Add items
    let item1 = ChecklistItem::new("write-core", "Write core logic");
    let item2 = ChecklistItem::new("write-tests", "Write tests");
    let item3 = ChecklistItem::new("document", "Document code");

    checklist.add_item(item1);
    checklist.add_item(item2);
    checklist.add_item(item3);

    // Check initial completion
    assert_eq!(checklist.completion_percentage(), 0.0);

    // Complete first item
    checklist.mark_item_complete("write-core").unwrap();
    assert!(checklist.completion_percentage() > 0.0);

    // Complete second item
    checklist.mark_item_complete("write-tests").unwrap();
    let completion = checklist.completion_percentage();
    assert!(
        (completion - 66.666664).abs() < 0.01,
        "Expected ~66.67%, got {}",
        completion
    );

    // Complete all
    checklist.mark_item_complete("document").unwrap();
    assert_eq!(checklist.completion_percentage(), 100.0);
}

#[test]
fn test_checklist_item_categories() {
    let mut checklist = Checklist::new(ProjectPhase::Devel);

    let item1 = ChecklistItem::new("setup-ci", "Set up CI/CD").with_category("Infrastructure");
    let item2 = ChecklistItem::new("unit-tests", "Write unit tests").with_category("Testing");
    let item3 = ChecklistItem::new("docs", "Write documentation").with_category("Documentation");

    checklist.add_item(item1);
    checklist.add_item(item2);
    checklist.add_item(item3);

    let markdown = checklist.export_to_markdown();
    assert!(markdown.contains("Infrastructure"));
    assert!(markdown.contains("Testing"));
    assert!(markdown.contains("Documentation"));
}

#[test]
fn test_checklist_manager_multi_phase() {
    let mut manager = ChecklistManager::new();

    // Initialize checklists first
    manager.load_checklist(ProjectPhase::Devel).ok();
    manager.load_checklist(ProjectPhase::Review).ok();

    // Add items
    let item1 = ChecklistItem::new("setup", "Setup project");
    let item2 = ChecklistItem::new("review-code", "Code review");

    assert!(manager.add_item(ProjectPhase::Devel, item1).is_ok());
    assert!(manager.add_item(ProjectPhase::Review, item2).is_ok());

    // Complete items
    assert!(manager
        .mark_item_complete(ProjectPhase::Devel, "setup")
        .is_ok());
    assert!(manager
        .mark_item_complete(ProjectPhase::Review, "review-code")
        .is_ok());
}

// ============================================
// Project Context Tests
// ============================================

#[test]
fn test_project_context_initialization() {
    let config = ProjectConfig::new("my-app");
    let ctx = ProjectContext::new("proj-1", config, PathBuf::from("."));

    assert_eq!(ctx.project_id, "proj-1");
    assert_eq!(ctx.config.project.name, "my-app");
    assert_eq!(ctx.phase_manager.current_phase(), ProjectPhase::Creation);
}

#[test]
fn test_project_context_phase_management() {
    let config = ProjectConfig::new("app");

    let mut ctx = ProjectContext::new("proj-1", config, PathBuf::from("."));

    // Test phase transition through context
    assert_eq!(ctx.phase_manager.current_phase(), ProjectPhase::Creation);
    ctx.phase_manager_mut()
        .transition_to(ProjectPhase::Devel, true)
        .ok();
    assert_eq!(ctx.phase_manager.current_phase(), ProjectPhase::Devel);
}

#[test]
fn test_project_context_status_summary() {
    let config = ProjectConfig::new("test-project");
    let ctx = ProjectContext::new("proj-123", config, PathBuf::from("."));

    let summary = ctx.status_summary();
    assert!(summary.contains("test-project"));
    assert!(summary.contains("creation"));
    assert!(summary.contains("Transitions: 0"));
}

#[test]
fn test_context_snapshot_roundtrip() {
    use crate::context::ContextSnapshot;

    let config = ProjectConfig::new("app");
    let ctx = ProjectContext::new("proj-1", config, PathBuf::from("."));

    // Create snapshot
    let snapshot = ContextSnapshot::from_context(&ctx);

    // Export to JSON
    let json = snapshot.to_json().unwrap();
    assert!(json.contains("proj-1"));
    assert!(json.contains("app"));

    // Import from JSON
    let restored = ContextSnapshot::from_json(&json).unwrap();
    assert_eq!(restored.project_id, snapshot.project_id);
    assert_eq!(restored.config.project.name, snapshot.config.project.name);

    // Restore to context
    let restored_ctx = restored.to_context(PathBuf::from(".")).unwrap();
    assert_eq!(restored_ctx.project_id, ctx.project_id);
}

// ============================================
// Project Config Tests
// ============================================

#[test]
fn test_project_config_defaults() {
    let config = ProjectConfig::default();
    assert!(!config.project.name.is_empty());
    assert_eq!(config.project.version, "0.1.0");
    assert_eq!(config.project.license, "MIT");
    assert!(config.validate().is_ok());
}

#[test]
fn test_project_config_validation() {
    let mut config = ProjectConfig::new("app");

    // Valid config
    assert!(config.validate().is_ok());

    // Invalid: no languages
    config.languages.clear();
    assert!(config.validate().is_err());

    // Fix and validate primary language
    config.languages = vec!["rust".to_string()];
    config.primary_language = "python".to_string();
    assert!(config.validate().is_err());

    // Valid again
    config.primary_language = "rust".to_string();
    assert!(config.validate().is_ok());
}

#[test]
fn test_project_types() {
    let project_types = vec![
        ProjectType::RustWeb,
        ProjectType::RustCli,
        ProjectType::RustEmbedded,
        ProjectType::MultiLang,
        ProjectType::NuShellScript,
    ];

    for ptype in project_types {
        let str_repr = ptype.to_string();
        assert!(!str_repr.is_empty());
    }
}

#[test]
fn test_project_mode_variants() {
    let modes = vec![
        ProjectMode::Standalone,
        ProjectMode::Vapora,
        ProjectMode::Provisioning,
    ];

    for mode in modes {
        let str_repr = mode.to_string();
        assert!(!str_repr.is_empty());
    }
}

// ============================================
// Integration Tests
// ============================================

#[test]
fn test_phase_transition_with_checklist_tracking() {
    let mut manager = PhaseManager::new(ProjectPhase::Creation);

    // Transition with checklist completion
    assert!(manager.transition_to(ProjectPhase::Devel, true).is_ok());

    let history = manager.history();
    assert_eq!(history.len(), 1);
    assert!(history[0].checklist_completed);
    assert_eq!(history[0].from, ProjectPhase::Creation);
    assert_eq!(history[0].to, ProjectPhase::Devel);
}

#[test]
fn test_full_project_lifecycle_simulation() {
    let mut config = ProjectConfig::new("syntaxis-test");
    config.project_type = ProjectType::RustWeb;
    config.mode = ProjectMode::Standalone;

    let mut ctx = ProjectContext::new("test-proj", config, PathBuf::from("."));

    // Simulate full lifecycle
    let phases = vec![
        ProjectPhase::Creation,
        ProjectPhase::Devel,
        ProjectPhase::Review,
        ProjectPhase::Publish,
    ];

    let mut expected_transitions = 0;
    for phase in phases {
        if ctx.phase_manager.can_transition(phase) && phase != ctx.phase_manager.current_phase() {
            ctx.phase_manager_mut().transition_to(phase, true).ok();
            expected_transitions += 1;
        }
    }

    assert!(expected_transitions > 0);
    assert_eq!(ctx.phase_manager.transition_count(), expected_transitions);
}

#[test]
fn test_tool_registry_builtin() {
    let registry = crate::tools::ToolRegistry::builtin();

    // All 5 built-in tools should be in registry
    assert!(registry.tools.contains_key("tracking"));
    assert!(registry.tools.contains_key("docs"));
    assert!(registry.tools.contains_key("provisioning"));
    assert!(registry.tools.contains_key("dev_system"));
    assert!(registry.tools.contains_key("presentation"));

    // Non-existent tool should not exist
    assert!(!registry.tools.contains_key("nonexistent"));
}
