use anyhow::Result;

use crate::config::{
    load_plane_settings, save_plane_settings, ApiToken, DefaultTarget, PlaneSettings,
    PlaneWorkspaceEntry, ProjectSlug, WorkspaceProjectScope, WorkspaceRegistry, WorkspaceSlug,
};

/// Interactive setup for Plane CLI: sets the API token, registers workspaces,
/// and configures default workspace and project preferences.
/// When called with no flags, displays the current configuration.
/// With --workspace and --token, registers a new workspace.
/// With --project, sets the default project for the active workspace.
#[derive(clap::Args)]
pub struct ConfigureSettingsArgs {
    #[arg(long, help = "Workspace slug to register or set as active")]
    workspace: Option<String>,
    #[arg(long, help = "API token for the workspace (required with --workspace on first add)")]
    token: Option<String>,
    #[arg(long, help = "Default project for the active workspace")]
    project: Option<String>,
}

/// Execution logic for the `plane config` subcommand
impl ConfigureSettingsArgs {
    /// Reads current settings, applies any requested changes from flags,
    /// and either displays the config or saves updates depending on arguments
    pub async fn execute(self) -> Result<()> {
        if self.workspace.is_none() && self.token.is_none() && self.project.is_none() {
            return display_current_configuration();
        }

        let current_plane_settings = load_plane_settings()?;
        let (current_target, current_registry) = current_plane_settings.into_parts();

        let mut workspace_entries = current_registry.into_workspace_entries();

        let mut active_workspace_slug = match current_target {
            DefaultTarget::Unconfigured => Option::<WorkspaceSlug>::None,
            DefaultTarget::WorkspaceOnly(workspace_slug) => Option::Some(workspace_slug),
        };

        if let Some(ref workspace_slug_text) = self.workspace {
            if let Some(ref token_text) = self.token {
                let validated_token: ApiToken = token_text.parse()?;
                let map_key_slug: WorkspaceSlug = workspace_slug_text.parse()?;
                workspace_entries.insert(map_key_slug, PlaneWorkspaceEntry::new(validated_token));
                println!("registered workspace '{}'", workspace_slug_text);
            }

            let active_slug: WorkspaceSlug = workspace_slug_text.parse()?;
            println!("active workspace set to '{}'", active_slug);
            active_workspace_slug = Option::Some(active_slug);
        }

        if let Some(ref project_text) = self.project {
            let validated_project: ProjectSlug = project_text.parse()?;
            let resolved_active = match &active_workspace_slug {
                Option::Some(slug) => slug,
                Option::None => {
                    anyhow::bail!("no active workspace — set one with --workspace first");
                }
            };

            match workspace_entries.get_mut(resolved_active) {
                Some(entry) => {
                    let current_token_text = entry.api_token().as_str().to_owned();
                    let refreshed_token: ApiToken = current_token_text.parse()?;
                    let updated_entry = PlaneWorkspaceEntry::new(refreshed_token)
                        .with_project(WorkspaceProjectScope::Scoped(validated_project));
                    *entry = updated_entry;
                    println!("default project for '{}' set to '{}'", resolved_active, project_text);
                }
                None => {
                    anyhow::bail!("workspace '{}' not found in config", resolved_active);
                }
            }
        }

        let new_default_target = match active_workspace_slug {
            Option::None => DefaultTarget::Unconfigured,
            Option::Some(workspace_slug) => DefaultTarget::WorkspaceOnly(workspace_slug),
        };

        let updated_settings = PlaneSettings::with_target(new_default_target)
            .with_workspaces(WorkspaceRegistry::from_entries(workspace_entries));

        save_plane_settings(&updated_settings)?;
        println!("configuration saved to ~/.plane-cli-requiem/config.toml");

        Ok(())
    }
}

/// Prints the current CLI configuration to stdout for review
fn display_current_configuration() -> Result<()> {
    let plane_settings = load_plane_settings()?;

    match plane_settings.default_target() {
        DefaultTarget::Unconfigured => {
            println!("no workspace configured");
            println!("run: plane config --workspace <slug> --token <api-key>");
        }
        DefaultTarget::WorkspaceOnly(workspace_slug) => {
            println!("active workspace: {}", workspace_slug);
            match plane_settings.workspaces().get(workspace_slug) {
                Some(entry) => match entry.project_scope() {
                    WorkspaceProjectScope::Scoped(project_slug) => {
                        println!("default project:  {}", project_slug);
                    }
                    WorkspaceProjectScope::Unscoped => {
                        println!("default project:  (none)");
                    }
                },
                None => {
                    println!("default project:  (none — workspace entry missing)");
                }
            }
        }
    }

    let workspace_count = plane_settings.workspaces().workspace_count();
    println!("registered workspaces: {}", workspace_count);

    for registered_slug in plane_settings.workspaces().slugs() {
        let project_label = match plane_settings.workspaces().get(registered_slug) {
            Some(entry) => match entry.project_scope() {
                WorkspaceProjectScope::Scoped(project_slug) => format!(" (project: {})", project_slug),
                WorkspaceProjectScope::Unscoped => String::new(),
            },
            None => String::new(),
        };
        println!("  - {}{}", registered_slug, project_label);
    }

    Ok(())
}
