//! Project management handler
//!
//! Handles project-related operations: listing, registering, selecting projects

use crate::ui_config;
use anyhow::{anyhow, Context, Result};
use colored::Colorize;
use syntaxis_core::persistence::{Database, SqliteDatabase};
use syntaxis_core::ProjectConfig;
use tools_shared::{
    detect_project_from_cwd, find_config_path_warn_conflicts, select_project, SelectableProject,
};

/// Handler for project management operations
#[derive(Debug)]
pub struct ProjectHandler;

impl ProjectHandler {
    /// List all projects in global database
    pub async fn list_projects() -> Result<()> {
        println!("📋 Projects in Global Database\n");

        // Find and open database from configuration
        let config_path = find_config_path_warn_conflicts("config.toml", None)
            .context("Failed to find project configuration")?;
        let config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        let project_root = config_path
            .parent()
            .and_then(|p| p.parent())
            .unwrap_or_else(|| std::path::Path::new("."));

        let db_path = project_root.join(&config.database_path);
        let db_path_str = db_path.to_string_lossy().to_string();

        let db = SqliteDatabase::new(&db_path_str)
            .await
            .context("Failed to open database")?;

        // Load all projects
        let projects = db
            .list_projects()
            .await
            .context("Failed to load projects")?;

        if projects.is_empty() {
            println!("  {}", "No projects found".dimmed());
            println!("\n  To create a project, run:");
            let app_name = ui_config::get_app_name();
            println!("    {} init <path>", app_name);
            return Ok(());
        }

        // Display as table
        println!(
            "  {:<25} {:<40} {:<15}",
            "Name".cyan(),
            "Path".normal(),
            "Phase".cyan()
        );
        println!("  {}", "─".repeat(85));

        for project in projects {
            println!(
                "  {:<25} {:<40} {:<15}",
                project.name,
                project.id,
                project.current_phase.yellow()
            );
        }

        Ok(())
    }

    /// Show details of a specific project
    pub async fn show_project(name: &str) -> Result<()> {
        println!("🔍 Project Details\n");

        // Find and open database from configuration
        let config_path = find_config_path_warn_conflicts("config.toml", None)
            .context("Failed to find project configuration")?;
        let config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        let project_root = config_path
            .parent()
            .and_then(|p| p.parent())
            .unwrap_or_else(|| std::path::Path::new("."));

        let db_path = project_root.join(&config.database_path);
        let db_path_str = db_path.to_string_lossy().to_string();

        let db = SqliteDatabase::new(&db_path_str)
            .await
            .context("Failed to open database")?;

        // Load all projects
        let projects = db
            .list_projects()
            .await
            .context("Failed to load projects")?;

        // Find project by name
        let project = projects
            .iter()
            .find(|p| p.name == name)
            .ok_or_else(|| anyhow!("Project not found: {}", name))?;

        println!("  {:<15} {}", "Name:", project.name.cyan());
        println!("  {:<15} {}", "ID:", project.id);
        println!("  {:<15} {}", "Version:", project.version);
        println!(
            "  {:<15} {}",
            "Phase:",
            format!("{:?}", project.current_phase).yellow()
        );
        println!("  {:<15} {}", "Type:", project.project_type);
        println!("  {:<15} {}", "Created:", project.created_at);
        println!("  {:<15} {}", "Updated:", project.updated_at);

        if !project.description.is_empty() {
            println!("  {:<15}", "Description:");
            println!("    {}", project.description);
        }

        Ok(())
    }

    /// Auto-detect current project
    pub fn detect_current() -> Result<()> {
        println!("🔍 Detecting Current Project\n");

        match detect_project_from_cwd("config.toml") {
            Some(detected) => {
                println!("  {:<15} {}", "Name:", detected.name.cyan());
                println!("  {:<15} {}", "Config:", detected.config_path.display());
                println!("  {:<15} {}", "Root:", detected.root_path.display());
                Ok(())
            }
            None => {
                println!(
                    "  {} No project detected in current directory or parents",
                    "✗".red()
                );
                println!("\n  Searched for: .project/lifecycle.toml");
                println!("  Checked locations:");

                let mut current = std::env::current_dir()?;
                loop {
                    println!("    {}", current.display());
                    if !current.pop() {
                        break;
                    }
                }

                println!("\n  To create a project here, run:");
                let app_name = ui_config::get_app_name();
                println!("    {} init .", app_name);

                Err(anyhow!("No project detected"))
            }
        }
    }

    /// Interactively select a project
    pub async fn select_from_list() -> Result<String> {
        println!("🔍 Selecting Project\n");

        // Find and open database from configuration
        let config_path = find_config_path_warn_conflicts("config.toml", None)
            .context("Failed to find project configuration")?;
        let config = ProjectConfig::load_from_file(&config_path)
            .context("Failed to load project configuration")?;

        let project_root = config_path
            .parent()
            .and_then(|p| p.parent())
            .unwrap_or_else(|| std::path::Path::new("."));

        let db_path = project_root.join(&config.database_path);
        let db_path_str = db_path.to_string_lossy().to_string();

        let db = SqliteDatabase::new(&db_path_str)
            .await
            .context("Failed to open database")?;

        // Load all projects
        let projects = db
            .list_projects()
            .await
            .context("Failed to load projects")?;

        if projects.is_empty() {
            return Err(anyhow!("No projects found in database"));
        }

        // Convert to selectable
        let selectable: Vec<SelectableProject> = projects
            .into_iter()
            .map(|p| SelectableProject {
                id: p.id.clone(),
                name: p.name,
                path: None,
                metadata: Some(format!("Phase: {:?}", p.current_phase)),
            })
            .collect();

        // Show selector
        select_project(selectable, "Select a project:", None)
            .map_err(|e| anyhow!("Selection failed: {}", e))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_list_projects_empty_db() {
        // This would require a test database setup
        // For now, just verify the handler exists
        let _handler = ProjectHandler;
    }

    #[test]
    fn test_detect_current_no_project() {
        // Test in temp directory without .project/
        use std::env;
        use tempfile::TempDir;

        let temp = TempDir::new().expect("Failed to create temp dir");
        let original_cwd = env::current_dir().unwrap();

        env::set_current_dir(temp.path()).expect("Failed to change dir");
        let result = ProjectHandler::detect_current();
        env::set_current_dir(original_cwd).expect("Failed to restore dir");

        assert!(result.is_err());
    }
}
