use anyhow::Result;
use comfy_table::presets::UTF8_FULL;
use comfy_table::{Cell, ContentArrangement, Table};

use crate::api::PlaneApiClient;
use crate::config::resolve_plane_session;
use crate::terminal_ui::OutputFormat;

/// Lists all projects the authenticated user can access in the active workspace.
/// Shows the project identifier (slug used for `--project` flags), display name,
/// and member count. Use this to discover project slugs when you don't know them.
/// Usage: `plane projects` or `plane projects --format json`
#[derive(clap::Args)]
pub struct ListProjectsArgs {
    /// Output format: table (default for TTY), json (default for pipes), csv
    #[arg(long)]
    format: Option<String>,
}

/// Execution logic for the `plane projects` subcommand
impl ListProjectsArgs {
    /// Fetches all projects in the active workspace and renders them
    /// in the selected output format
    pub async fn execute(self) -> Result<()> {
        let plane_session = resolve_plane_session()?;
        let api_client = PlaneApiClient::try_new(plane_session)?;

        let workspace_projects = api_client.list_projects().await?;

        let selected_format = match &self.format {
            Option::Some(format_text) => format_text.parse()?,
            Option::None => OutputFormat::detect_from_terminal(),
        };

        match selected_format {
            OutputFormat::Table => render_projects_table(&workspace_projects),
            OutputFormat::Json => render_projects_json(&workspace_projects),
            OutputFormat::Csv => render_projects_csv(&workspace_projects),
        }

        Ok(())
    }
}

fn render_projects_table(workspace_projects: &[crate::api::PlaneProject]) {
    if workspace_projects.is_empty() {
        println!("No projects found in this workspace.");
        return;
    }

    let mut terminal_table = Table::new();
    terminal_table
        .load_preset(UTF8_FULL)
        .set_content_arrangement(ContentArrangement::Dynamic)
        .set_header(vec![
            Cell::new("Identifier"),
            Cell::new("Name"),
        ]);

    for project_entry in workspace_projects {
        terminal_table.add_row(vec![
            Cell::new(project_entry.identifier()),
            Cell::new(project_entry.display_name()),
        ]);
    }

    println!("{}", terminal_table);
}

fn render_projects_json(workspace_projects: &[crate::api::PlaneProject]) {
    let json_entries: Vec<serde_json::Value> = workspace_projects
        .iter()
        .map(|project_entry| {
            serde_json::json!({
                "identifier": project_entry.identifier(),
                "name": project_entry.display_name(),
                "id": project_entry.id().to_string(),
            })
        })
        .collect();

    match serde_json::to_string_pretty(&json_entries) {
        Ok(formatted_json) => println!("{}", formatted_json),
        Err(serialization_error) => {
            eprintln!("error serializing JSON: {}", serialization_error)
        }
    }
}

fn render_projects_csv(workspace_projects: &[crate::api::PlaneProject]) {
    println!("identifier,name,id");
    for project_entry in workspace_projects {
        println!(
            "{},\"{}\",{}",
            project_entry.identifier(),
            project_entry.display_name().replace('"', "\"\""),
            project_entry.id(),
        );
    }
}
