mod documentation;
mod gitlab_ci;
mod pipeline;
mod workspace;

use colored::Colorize;
use lmrc_config_validator::LmrcConfig;
use std::fs;
use std::path::{Path, PathBuf};

use crate::error::Result;

pub struct ProjectGenerator {
    config: LmrcConfig,
    project_path: PathBuf,
}

impl ProjectGenerator {
    pub fn new(config: LmrcConfig, project_path: PathBuf) -> Self {
        Self {
            config,
            project_path,
        }
    }

    pub fn project_path(&self) -> &Path {
        &self.project_path
    }

    pub async fn generate(&self) -> Result<()> {
        println!("{}", "Generating project structure...".yellow());

        // Create root directory
        fs::create_dir_all(&self.project_path)?;

        // Create directory structure
        self.create_directory_structure()?;

        // Generate workspace Cargo.toml
        workspace::generate_workspace_toml(&self.project_path, &self.config)?;

        // Generate configuration file
        self.generate_config_file()?;

        // Generate applications
        self.generate_applications()?;

        // Generate libs directory with placeholders
        self.generate_libs()?;

        // Generate pipeline application
        pipeline::generate_pipeline_app(&self.project_path, &self.config)?;

        // Generate GitLab CI configuration
        gitlab_ci::generate_gitlab_ci(&self.project_path, &self.config)?;

        // Generate documentation
        documentation::generate_docs(&self.project_path, &self.config)?;

        // Generate Docker files
        self.generate_docker_files()?;

        // Generate .gitignore
        self.generate_gitignore()?;

        Ok(())
    }

    fn create_directory_structure(&self) -> Result<()> {
        let dirs = vec!["apps", "libs", "docs", "docker", "infra"];

        for dir in dirs {
            let path = self.project_path.join(dir);
            fs::create_dir_all(&path)?;
            println!("  {} {}", "Created:".green(), path.display());
        }

        Ok(())
    }

    fn generate_config_file(&self) -> Result<()> {
        let config_content = self.config.to_toml_string()?;
        let config_path = self.project_path.join("lmrc.toml");
        fs::write(&config_path, config_content)?;
        println!("  {} {}", "Created:".green(), config_path.display());
        Ok(())
    }

    fn generate_applications(&self) -> Result<()> {
        use lmrc_toml_writer::PackageToml;

        for app in &self.config.apps.applications {
            let app_path = self.project_path.join("apps").join(&app.name);
            fs::create_dir_all(&app_path)?;

            // Create a basic Rust binary project using PackageToml builder
            let cargo_toml = PackageToml::new(&app.name)
                .version("0.1.0")
                .edition("2021")
                .dependency_inline("tokio", r#"{ version = "1.0", features = ["full"] }"#)
                .build();

            fs::write(app_path.join("Cargo.toml"), cargo_toml)?;

            // Create src directory and main.rs
            let src_dir = app_path.join("src");
            fs::create_dir_all(&src_dir)?;

            let main_rs = r#"#[tokio::main]
async fn main() {
    println!("Hello from {}!");
}
"#;

            fs::write(src_dir.join("main.rs"), main_rs)?;
            println!("  {} apps/{}", "Created:".green(), app.name);
        }

        Ok(())
    }

    fn generate_libs(&self) -> Result<()> {
        let libs_path = self.project_path.join("libs");
        let readme = r#"# Shared Libraries

This directory contains shared libraries used across multiple applications.

Place reusable code, utilities, and shared logic here.
"#;
        fs::write(libs_path.join("README.md"), readme)?;
        println!("  {} libs/README.md", "Created:".green());
        Ok(())
    }

    fn generate_docker_files(&self) -> Result<()> {
        let docker_path = self.project_path.join("docker");

        // Generate Dockerfile template for applications
        let dockerfile = r#"# Build stage
FROM rust:1.75-slim as builder

WORKDIR /app
COPY . .

RUN cargo build --release

# Runtime stage
FROM debian:bookworm-slim

RUN apt-get update && \
    apt-get install -y ca-certificates && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY --from=builder /app/target/release/app /app/app

ENTRYPOINT ["/app/app"]
"#;

        fs::write(docker_path.join("Dockerfile"), dockerfile)?;
        println!("  {} docker/Dockerfile", "Created:".green());

        // Generate docker-compose.yml for local development
        let docker_compose = format!(
            r#"version: '3.8'

services:
  postgres:
    image: postgres:{}
    environment:
      POSTGRES_DB: {}
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
"#,
            self.config
                .infrastructure
                .postgres
                .as_ref()
                .map(|p| p.version.as_str())
                .unwrap_or("16"),
            self.config
                .infrastructure
                .postgres
                .as_ref()
                .map(|p| p.database_name.as_str())
                .unwrap_or("myapp")
        );

        fs::write(docker_path.join("docker-compose.yml"), docker_compose)?;
        println!("  {} docker/docker-compose.yml", "Created:".green());

        Ok(())
    }

    fn generate_gitignore(&self) -> Result<()> {
        let gitignore = r#"# Rust
/target/
**/*.rs.bk
*.pdb
Cargo.lock

# IDE
.idea/
.vscode/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Environment
.env
.env.local

# Secrets
secrets/
*.pem
*.key
"#;

        let gitignore_path = self.project_path.join(".gitignore");
        fs::write(&gitignore_path, gitignore)?;
        println!("  {} .gitignore", "Created:".green());

        Ok(())
    }
}
