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

use crate::api::{PlaneApiClient, PlaneState, StateGroup};
use crate::config::{ProjectScope, resolve_plane_session};
use crate::terminal_ui::OutputFormat;

/// Fetches and renders all workflow states defined in the active project.
/// Each state belongs to a canonical group (backlog, unstarted, started,
/// completed, cancelled) that drives board columns and metrics.
/// Accepts --project and --format overrides.
#[derive(clap::Args)]
pub struct ListStatesArgs {
    /// Project slug to query (overrides the configured default project)
    #[arg(long, default_value = "")]
    project: String,
    /// Output format: table (default for TTY), json (default for pipes), csv
    #[arg(long, default_value = "")]
    format: String,
}

/// Renders state collections in table, JSON, and CSV formats with group coloring
struct ListStatesRenderer<'a> {
    /// The state collection to render
    project_states: &'a [PlaneState],
}

/// Fetches states from the API and renders them in the selected format
impl ListStatesArgs {
    /// Resolves the project, fetches workflow states, and renders them
    pub async fn execute(self) -> Result<()> {
        let plane_session = resolve_plane_session()?;
        let api_client = PlaneApiClient::try_new(plane_session)?;

        let target_project_slug = resolve_list_states_project(&self.project, &api_client)?;
        let resolved_project = api_client
            .find_project_by_slug(&target_project_slug)
            .await?;

        let project_states = api_client.list_states(resolved_project.id()).await?;

        let selected_format = resolve_list_states_format(&self.format)?;

        let renderer = ListStatesRenderer {
            project_states: &project_states,
        };

        match selected_format {
            OutputFormat::Table => renderer.print_table(),
            OutputFormat::Json => renderer.print_json(),
            OutputFormat::Csv => renderer.print_csv(),
        }

        Ok(())
    }
}

/// Resolves a project slug string: uses the explicit value when non-empty,
/// falls back to the configured default when empty
fn resolve_list_states_project(
    project_text: &str,
    api_client: &PlaneApiClient,
) -> Result<crate::config::ProjectSlug> {
    match project_text {
        "" => match api_client.project_scope() {
            ProjectScope::Scoped(default_project) => default_project.as_str().parse(),
            ProjectScope::ExplicitOnly => {
                anyhow::bail!(
                    "no default project configured — pass --project or run: \
                     plane config --project <slug>"
                );
            }
        },
        explicit => explicit.parse(),
    }
}

/// Resolves a format string: uses the explicit value when non-empty,
/// falls back to TTY auto-detection when empty
fn resolve_list_states_format(format_text: &str) -> Result<OutputFormat> {
    match format_text {
        "" => Ok(OutputFormat::detect_from_terminal()),
        explicit => explicit.parse(),
    }
}

/// Table, JSON, and CSV rendering for workflow state collections
impl<'a> ListStatesRenderer<'a> {
    /// Renders states as a colored terminal table with name, group, and color columns.
    /// State names are colorized according to their group classification.
    fn print_table(&self) {
        if self.project_states.is_empty() {
            println!("No states found.");
            return;
        }

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

        for state_entry in self.project_states {
            let colored_name = colorize_list_states_display(state_entry);
            let group_label = format_list_states_group(state_entry.state_group());

            terminal_table.add_row(vec![
                Cell::new(colored_name),
                Cell::new(group_label),
                Cell::new(state_entry.color_hex().dimmed().to_string()),
            ]);
        }

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

    /// Renders states as a JSON array with id, name, group, and color fields
    fn print_json(&self) {
        let json_entries: Vec<serde_json::Value> = self
            .project_states
            .iter()
            .map(|state_entry| {
                serde_json::json!({
                    "id": state_entry.id().to_string(),
                    "name": state_entry.display_name(),
                    "group": format!("{:?}", state_entry.state_group()),
                    "color": state_entry.color_hex(),
                })
            })
            .collect();

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

    /// Renders states as CSV with id, name, group, and color columns
    fn print_csv(&self) {
        println!("id,name,group,color");
        for state_entry in self.project_states {
            println!(
                "{},\"{}\",{:?},{}",
                state_entry.id().to_string(),
                state_entry.display_name().replace('"', "\"\""),
                state_entry.state_group(),
                state_entry.color_hex(),
            );
        }
    }
}

/// Colorizes a state display name based on its canonical workflow group
fn colorize_list_states_display(resolved_state: &PlaneState) -> String {
    match resolved_state.state_group() {
        StateGroup::Backlog => resolved_state.display_name().dimmed().to_string(),
        StateGroup::Unstarted => resolved_state.display_name().white().to_string(),
        StateGroup::Started => resolved_state.display_name().yellow().to_string(),
        StateGroup::Completed => resolved_state.display_name().green().to_string(),
        StateGroup::Cancelled => resolved_state.display_name().red().to_string(),
    }
}

/// Returns a human-readable group label for terminal display
fn format_list_states_group(state_group: StateGroup) -> String {
    match state_group {
        StateGroup::Backlog => "backlog".dimmed().to_string(),
        StateGroup::Unstarted => "unstarted".white().to_string(),
        StateGroup::Started => "started".yellow().to_string(),
        StateGroup::Completed => "completed".green().to_string(),
        StateGroup::Cancelled => "cancelled".red().to_string(),
    }
}
