use colored::Colorize;
use lmrc_config_validator::LmrcConfig;
use std::fs;
use std::path::Path;

use crate::error::Result;

pub fn generate_pipeline_app(project_path: &Path, config: &LmrcConfig) -> Result<()> {
    let pipeline_path = project_path.join("infra").join("pipeline");
    fs::create_dir_all(&pipeline_path)?;

    // Generate Cargo.toml for pipeline app
    generate_pipeline_cargo_toml(&pipeline_path, config)?;

    // Generate main.rs
    generate_pipeline_main(&pipeline_path, config)?;

    println!("  {} infra/pipeline", "Created:".green());
    println!(
        "  {} Pipeline uses lmrc-pipeline library",
        "Note:".bright_blue()
    );

    Ok(())
}

fn generate_pipeline_cargo_toml(pipeline_path: &Path, _config: &LmrcConfig) -> Result<()> {
    use lmrc_toml_writer::PackageToml;

    let builder = PackageToml::new("pipeline")
        .workspace_version()
        .workspace_edition()
        .bin("pipeline", "src/main.rs")
        // Core dependencies
        .workspace_dependency("tokio")
        .workspace_dependency("clap")
        .workspace_dependency("anyhow")
        // LMRC Pipeline library - provides all the pipeline steps
        .workspace_dependency("lmrc-pipeline")
        .workspace_dependency("lmrc-config-validator");

    let cargo_toml = builder.build();
    fs::write(pipeline_path.join("Cargo.toml"), cargo_toml)?;

    Ok(())
}

fn generate_pipeline_main(pipeline_path: &Path, _config: &LmrcConfig) -> Result<()> {
    #[allow(clippy::useless_format)]
    let main_rs = format!(
        r#"use clap::{{Parser, Subcommand}};
use lmrc_config_validator::ProjectConfig;
use lmrc_pipeline::{{Pipeline, PipelineContext}};
use lmrc_pipeline::steps::*;

#[derive(Parser)]
#[command(name = "pipeline")]
#[command(about = "LMRC Stack deployment pipeline", version)]
struct Cli {{
    #[command(subcommand)]
    command: Commands,
}}

#[derive(Subcommand)]
enum Commands {{
    /// Check code formatting and linting
    Check {{
        /// Run format check
        #[arg(long)]
        format: bool,

        /// Run clippy
        #[arg(long)]
        clippy: bool,
    }},

    /// Run tests
    Test,

    /// Build applications
    Build {{
        /// Build in release mode
        #[arg(long)]
        release: bool,
    }},

    /// Build Docker images
    DockerBuild,

    /// Provision infrastructure (servers, networks, etc.)
    Provision,

    /// Setup infrastructure (K8s, databases, etc.)
    Setup,

    /// Deploy applications
    Deploy,

    /// Run full pipeline (provision + setup + deploy)
    Full,
}}

#[tokio::main]
async fn main() -> anyhow::Result<()> {{
    let cli = Cli::parse();

    // Load configuration
    let config = ProjectConfig::from_file("lmrc.toml")?;

    // Execute command
    match cli.command {{
        Commands::Check {{ format, clippy }} => {{
            let mut pipeline = Pipeline::new(PipelineContext::new(config));

            if format {{
                pipeline = pipeline.add_step(FormatCheckStep::new());
            }}
            if clippy {{
                pipeline = pipeline.add_step(ClippyStep::new());
            }}

            // If no flags specified, run both
            if !format && !clippy {{
                pipeline = pipeline
                    .add_step(FormatCheckStep::new())
                    .add_step(ClippyStep::new());
            }}

            pipeline.run().await?;
        }}

        Commands::Test => {{
            Pipeline::new(PipelineContext::new(config))
                .add_step(TestStep::new())
                .run()
                .await?;
        }}

        Commands::Build {{ release }} => {{
            let mut step = BuildStep::new();
            if release {{
                step = step.release();
            }}

            Pipeline::new(PipelineContext::new(config))
                .add_step(step)
                .run()
                .await?;
        }}

        Commands::DockerBuild => {{
            Pipeline::new(PipelineContext::new(config))
                .add_step(DockerBuildStep::new())
                .run()
                .await?;
        }}

        Commands::Provision => {{
            Pipeline::new(PipelineContext::new(config))
                .add_step(ProvisionStep::new())
                .run()
                .await?;
        }}

        Commands::Setup => {{
            Pipeline::new(PipelineContext::new(config))
                .add_step(SetupK8sStep::new())
                .add_step(SetupDatabaseStep::new())
                .add_step(SetupDnsStep::new())
                .run()
                .await?;
        }}

        Commands::Deploy => {{
            Pipeline::new(PipelineContext::new(config))
                .add_step(DeployStep::new())
                .run()
                .await?;
        }}

        Commands::Full => {{
            Pipeline::new(PipelineContext::new(config))
                // CI checks
                .add_step(FormatCheckStep::new())
                .add_step(ClippyStep::new())
                .add_step(TestStep::new())
                // Build
                .add_step(BuildStep::new().release())
                .add_step(DockerBuildStep::new())
                // Infrastructure
                .add_step(ProvisionStep::new())
                .add_step(SetupK8sStep::new())
                .add_step(SetupDatabaseStep::new())
                .add_step(SetupDnsStep::new())
                // Deploy
                .add_step(DeployStep::new())
                .run()
                .await?;
        }}
    }}

    Ok(())
}}
"#
    );

    let src_path = pipeline_path.join("src");
    fs::create_dir_all(&src_path)?;
    fs::write(src_path.join("main.rs"), main_rs)?;

    Ok(())
}
