use colored::Colorize;
use inquire::{Confirm, Select, Text};
use lmrc_config_validator::{
    ApplicationEntry, CloudflareConfig, GitLabConfig, HetznerConfig, K3sConfig, LmrcConfig,
    PostgresConfig, ProjectConfig, ProviderConfig, providers,
};

use crate::error::Result;

pub struct InteractivePrompt;

impl InteractivePrompt {
    /// Run interactive prompts to build configuration
    pub fn run() -> Result<LmrcConfig> {
        println!(
            "\n{}\n",
            "Welcome to LMRC Stack Project Generator!".green().bold()
        );
        println!("Let's configure your infrastructure project.\n");

        // Project information
        let project = Self::prompt_project()?;

        // Provider selection
        let providers = Self::prompt_providers()?;

        // Applications
        let apps = Self::prompt_applications()?;

        // Infrastructure configuration
        let infrastructure = Self::prompt_infrastructure(&providers)?;

        Ok(LmrcConfig {
            project,
            providers,
            apps,
            infrastructure,
        })
    }

    fn prompt_project() -> Result<ProjectConfig> {
        println!("{}", "=== Project Information ===".cyan().bold());

        let name = Text::new("Project name:")
            .with_help_message("Alphanumeric with hyphens/underscores only")
            .prompt()?;

        let description = Text::new("Project description:")
            .with_default("My LMRC Stack infrastructure project")
            .prompt()?;

        Ok(ProjectConfig { name, description })
    }

    fn prompt_providers() -> Result<ProviderConfig> {
        println!("\n{}", "=== Provider Selection ===".cyan().bold());

        let server = Select::new(
            "Select server provider:",
            providers::SERVER_PROVIDERS.to_vec(),
        )
        .prompt()?
        .to_string();

        let kubernetes = Select::new(
            "Select Kubernetes distribution:",
            providers::KUBERNETES_PROVIDERS.to_vec(),
        )
        .with_help_message("Distribution to install (future: eks, gke, aks)")
        .prompt()?
        .to_string();

        let database = Select::new(
            "Select database provider:",
            providers::DATABASE_PROVIDERS.to_vec(),
        )
        .prompt()?
        .to_string();

        let dns = Select::new("Select DNS provider:", providers::DNS_PROVIDERS.to_vec())
            .prompt()?
            .to_string();

        let git = Select::new("Select Git provider:", providers::GIT_PROVIDERS.to_vec())
            .prompt()?
            .to_string();

        Ok(ProviderConfig {
            server,
            kubernetes,
            database,
            dns,
            git,
        })
    }

    fn prompt_applications() -> Result<lmrc_config_validator::AppsConfig> {
        println!("\n{}", "=== Applications ===".cyan().bold());

        let mut applications = Vec::new();

        loop {
            let app_name = Text::new("Application name:")
                .with_help_message("Leave empty to finish adding applications")
                .prompt()?;

            if app_name.trim().is_empty() {
                if applications.is_empty() {
                    println!("{}", "At least one application is required!".yellow());
                    continue;
                }
                break;
            }

            let app_type = Select::new(
                "Application type:",
                vec!["api", "web", "worker", "cli", "service"],
            )
            .prompt()?
            .to_string();

            applications.push(ApplicationEntry {
                name: app_name,
                app_type,
            });

            let add_more = Confirm::new("Add another application?")
                .with_default(false)
                .prompt()?;

            if !add_more {
                break;
            }
        }

        Ok(lmrc_config_validator::AppsConfig { applications })
    }

    fn prompt_infrastructure(
        providers: &ProviderConfig,
    ) -> Result<lmrc_config_validator::InfrastructureConfig> {
        println!("\n{}", "=== Infrastructure Configuration ===".cyan().bold());

        let mut config = lmrc_config_validator::InfrastructureConfig {
            hetzner: None,
            k3s: None,
            postgres: None,
            cloudflare: None,
            gitlab: None,
        };

        // Server provider config
        if providers.server == "hetzner" {
            println!("\n{}", "Hetzner Configuration:".yellow());
            config.hetzner = Some(Self::prompt_hetzner()?);
        }

        // Kubernetes distribution config
        if providers.kubernetes == "k3s" {
            println!("\n{}", "K3s Configuration:".yellow());
            config.k3s = Some(Self::prompt_k3s()?);
        }
        // Future: handle eks, gke, aks, k0s, etc.

        // Database config
        if providers.database == "postgres" {
            println!("\n{}", "PostgreSQL Configuration:".yellow());
            config.postgres = Some(Self::prompt_postgres()?);
        }

        // DNS config
        if providers.dns == "cloudflare" {
            println!("\n{}", "Cloudflare Configuration:".yellow());
            config.cloudflare = Some(Self::prompt_cloudflare()?);
        }

        // Git config
        if providers.git == "gitlab" {
            println!("\n{}", "GitLab Configuration:".yellow());
            config.gitlab = Some(Self::prompt_gitlab()?);
        }

        Ok(config)
    }

    fn prompt_hetzner() -> Result<HetznerConfig> {
        let server_type = Select::new(
            "Server type:",
            vec![
                "cx11", "cx21", "cx31", "cx41", "cx51", "cpx11", "cpx21", "cpx31",
            ],
        )
        .with_help_message("See https://www.hetzner.com/cloud for details")
        .prompt()?
        .to_string();

        let location = Select::new(
            "Server location:",
            vec!["nbg1", "fsn1", "hel1", "ash", "hil"],
        )
        .with_help_message("nbg1=Nuremberg, fsn1=Falkenstein, hel1=Helsinki")
        .prompt()?
        .to_string();

        let count = Text::new("Number of servers:")
            .with_default("1")
            .prompt()?
            .parse::<u32>()
            .unwrap_or(1);

        Ok(HetznerConfig {
            server_type,
            location,
            count,
        })
    }

    fn prompt_k3s() -> Result<K3sConfig> {
        let enable_traefik = Confirm::new("Enable Traefik ingress controller?")
            .with_default(true)
            .prompt()?;

        Ok(K3sConfig {
            version: None,
            enable_traefik,
        })
    }

    fn prompt_postgres() -> Result<PostgresConfig> {
        let version = Select::new("PostgreSQL version:", vec!["16", "15", "14", "13"])
            .with_help_message("Latest stable version recommended")
            .prompt()?
            .to_string();

        let database_name = Text::new("Database name:").with_default("myapp").prompt()?;

        Ok(PostgresConfig {
            version,
            database_name,
        })
    }

    fn prompt_cloudflare() -> Result<CloudflareConfig> {
        let domain = Text::new("Primary domain:")
            .with_help_message("e.g., example.com")
            .prompt()?;

        let proxied = Confirm::new("Enable Cloudflare proxy?")
            .with_default(true)
            .with_help_message("Provides DDoS protection and CDN")
            .prompt()?;

        Ok(CloudflareConfig { domain, proxied })
    }

    fn prompt_gitlab() -> Result<GitLabConfig> {
        let url = Text::new("GitLab instance URL:")
            .with_default("https://gitlab.com")
            .prompt()?;

        let namespace = Text::new("Project namespace/group:")
            .with_help_message("e.g., mycompany or myusername")
            .prompt()?;

        Ok(GitLabConfig { url, namespace })
    }
}
