//! Package functionality for distributing Rustelo components

use std::path::Path;

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

/// Package configuration
#[derive(Debug, Serialize, Deserialize)]
pub struct PackageConfig {
    pub name: String,
    pub version: String,
    pub description: String,
    pub author: String,
    pub license: String,
    pub include: Vec<PackageTarget>,
    pub output_format: PackageFormat,
}

/// What can be packaged for distribution
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PackageTarget {
    Pages,
    Components,
    Templates,
    Styles,
    Scripts,
    Assets,
}

/// Output format for packages
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PackageFormat {
    Crate,    // Rust crate
    Template, // Template archive
    Bundle,   // Full application bundle
}

/// Create package for distribution (CLI interface)
pub fn create_package(format: &str) -> Result<()> {
    match format {
        "crate" => create_crate_package_cli(),
        "template" => create_template_package_cli(),
        "bundle" => create_bundle_package_cli(),
        "docker" => create_docker_package(),
        _ => {
            println!("⚠️ Unknown package format: {}", format);
            println!("📋 Available formats: crate, template, bundle, docker");
            Ok(())
        }
    }
}

/// Package project components for distribution (full config)
pub fn package_project(config: &PackageConfig, output_dir: &str) -> Result<()> {
    println!("📦 Packaging project: {}", config.name);
    println!("   Version: {}", config.version);
    println!("   Format: {:?}", config.output_format);

    std::fs::create_dir_all(output_dir).context("Failed to create output directory")?;

    for target in &config.include {
        package_target(target, output_dir)?;
    }

    match config.output_format {
        PackageFormat::Crate => create_crate_package(config, output_dir),
        PackageFormat::Template => create_template_package(config, output_dir),
        PackageFormat::Bundle => create_bundle_package(config, output_dir),
    }
}

fn package_target(target: &PackageTarget, _output_dir: &str) -> Result<()> {
    match target {
        PackageTarget::Pages => {
            println!("  📄 Packaging pages...");
            // Copy page files
        }
        PackageTarget::Components => {
            println!("  🧩 Packaging components...");
            // Copy component files
        }
        PackageTarget::Templates => {
            println!("  📋 Packaging templates...");
            // Copy template files
        }
        PackageTarget::Styles => {
            println!("  🎨 Packaging styles...");
            // Copy CSS/style files
        }
        PackageTarget::Scripts => {
            println!("  📜 Packaging scripts...");
            // Copy JavaScript/script files
        }
        PackageTarget::Assets => {
            println!("  🖼️ Packaging assets...");
            // Copy asset files
        }
    }
    Ok(())
}

/// Create crate package (CLI version)
fn create_crate_package_cli() -> Result<()> {
    println!("  🦀 Creating Rust crate package...");

    // Ensure dist directory exists
    let dist_dir = "dist";
    std::fs::create_dir_all(dist_dir)?;

    // Run cargo package
    println!("  🔧 Running cargo package...");
    let output = std::process::Command::new("cargo")
        .args(["package", "--allow-dirty"])
        .output()?;

    if output.status.success() {
        println!("  ✅ Crate package created successfully!");
        println!("  📁 Package available in: target/package/");
    } else {
        println!("  ❌ Package creation failed:");
        println!("{}", String::from_utf8_lossy(&output.stderr));
    }

    Ok(())
}

fn create_crate_package(_config: &PackageConfig, _output_dir: &str) -> Result<()> {
    println!("  🦀 Creating Rust crate package...");
    // Generate Cargo.toml
    // Copy source files
    // Create README.md
    Ok(())
}

/// Create template package (CLI version)
fn create_template_package_cli() -> Result<()> {
    println!("  📄 Creating template package (unified architecture)...");

    // Support unified template architecture
    let project_templates_dir = std::env::var("RUSTELO_PROJECT_TEMPLATES_PATH")
        .unwrap_or_else(|_| "rustelo-templates/project".to_string());
    let crate_templates_dir = std::env::var("RUSTELO_CRATE_TEMPLATES_PATH")
        .unwrap_or_else(|_| "rustelo-templates/crates".to_string());
    let feature_templates_dir = std::env::var("RUSTELO_FEATURE_TEMPLATES_PATH")
        .unwrap_or_else(|_| "rustelo-templates/features".to_string());

    let dist_dir = "dist/templates";

    // Create dist directory structure
    std::fs::create_dir_all(format!("{}/project", dist_dir))?;
    std::fs::create_dir_all(format!("{}/crates", dist_dir))?;
    std::fs::create_dir_all(format!("{}/features", dist_dir))?;

    let mut packaged_count = 0;

    // Copy project templates if they exist
    if Path::new(&project_templates_dir).exists() {
        copy_dir_recursive(&project_templates_dir, format!("{}/project", dist_dir))?;
        println!("  ✅ Project templates packaged");
        packaged_count += 1;
    } else {
        println!(
            "  ⚠️ No project templates found at: {}",
            project_templates_dir
        );
    }

    // Copy crate templates if they exist
    if Path::new(&crate_templates_dir).exists() {
        copy_dir_recursive(&crate_templates_dir, format!("{}/crates", dist_dir))?;
        println!("  ✅ Crate templates packaged");
        packaged_count += 1;
    } else {
        println!("  ⚠️ No crate templates found at: {}", crate_templates_dir);
    }

    // Copy feature templates if they exist
    if Path::new(&feature_templates_dir).exists() {
        copy_dir_recursive(&feature_templates_dir, format!("{}/features", dist_dir))?;
        println!("  ✅ Feature templates packaged");
        packaged_count += 1;
    } else {
        println!(
            "  ⚠️ No feature templates found at: {}",
            feature_templates_dir
        );
    }

    if packaged_count > 0 {
        // Create unified template manifest
        create_unified_template_manifest(dist_dir)?;
        println!(
            "  📦 Templates packaged to: {} ({} types)",
            dist_dir, packaged_count
        );
    } else {
        println!("  ⚠️ No templates found to package");
    }

    Ok(())
}

fn create_template_package(_config: &PackageConfig, _output_dir: &str) -> Result<()> {
    println!("  📄 Creating template package...");
    // Create template.toml
    // Package template files
    // Create documentation
    Ok(())
}

/// Create bundle package (CLI version)
fn create_bundle_package_cli() -> Result<()> {
    println!("  📦 Creating application bundle...");

    let dist_dir = "dist/bundle";
    std::fs::create_dir_all(dist_dir)?;

    // Build release version
    println!("  🔧 Building release version...");
    let output = std::process::Command::new("cargo")
        .args(["build", "--release"])
        .output()?;

    if !output.status.success() {
        println!("  ❌ Build failed:");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        return Ok(());
    }

    // Copy binary
    if Path::new("target/release/tools").exists() {
        std::fs::copy("target/release/tools", format!("{}/tools", dist_dir))?;
        println!("  ✅ Binary copied to bundle");
    }

    // Copy essential files
    for file in ["Cargo.toml", "README.md", "LICENSE"] {
        if Path::new(file).exists() {
            std::fs::copy(file, format!("{}/{}", dist_dir, file))?;
        }
    }

    println!("  ✅ Application bundle created: {}", dist_dir);
    Ok(())
}

fn create_bundle_package(_config: &PackageConfig, _output_dir: &str) -> Result<()> {
    println!("  📦 Creating application bundle...");
    // Create complete application package
    // Include all dependencies
    // Generate deployment scripts
    Ok(())
}

/// Load package configuration
pub fn load_package_config<P: AsRef<Path>>(config_path: P) -> Result<PackageConfig> {
    let content =
        std::fs::read_to_string(config_path).context("Failed to read package configuration")?;

    let config: PackageConfig =
        toml::from_str(&content).context("Failed to parse package configuration")?;

    Ok(config)
}

/// Create default package configuration
pub fn create_default_package_config(name: &str) -> PackageConfig {
    PackageConfig {
        name: name.to_string(),
        version: "0.1.0".to_string(),
        description: format!("Rustelo project: {}", name),
        author: "Rustelo Developer".to_string(),
        license: "MIT".to_string(),
        include: vec![
            PackageTarget::Pages,
            PackageTarget::Components,
            PackageTarget::Templates,
            PackageTarget::Styles,
        ],
        output_format: PackageFormat::Template,
    }
}

/// Create Docker package
fn create_docker_package() -> Result<()> {
    println!("  🐳 Creating Docker package...");

    // Check if Dockerfile exists
    if !Path::new("Dockerfile").exists() {
        create_default_dockerfile()?;
    }

    // Build Docker image
    println!("  🔧 Building Docker image...");
    let output = std::process::Command::new("docker")
        .args(["build", "-t", "rustelo-tools:latest", "."])
        .output()?;

    if output.status.success() {
        println!("  ✅ Docker image built successfully!");
        println!("  🐳 Image tagged as: rustelo-tools:latest");
    } else {
        println!("  ❌ Docker build failed:");
        println!("{}", String::from_utf8_lossy(&output.stderr));
    }

    Ok(())
}

/// Copy directory recursively
fn copy_dir_recursive<P1: AsRef<Path>, P2: AsRef<Path>>(src: P1, dst: P2) -> Result<()> {
    let src = src.as_ref();
    let dst = dst.as_ref();

    std::fs::create_dir_all(dst)?;

    for entry in std::fs::read_dir(src)? {
        let entry = entry?;
        let src_path = entry.path();
        let dst_path = dst.join(entry.file_name());

        if src_path.is_dir() {
            copy_dir_recursive(&src_path, &dst_path)?;
        } else {
            std::fs::copy(&src_path, &dst_path)?;
        }
    }

    Ok(())
}

/// Create template manifest file
fn create_template_manifest(dist_dir: &str) -> Result<()> {
    let manifest_content = r#"[package]
name = "rustelo-templates"
version = "0.1.0"
description = "Rustelo framework template collection"
authors = ["Rustelo Team"]

[templates]
# Available templates
page = "page.tera"
component = "component.tera"
route = "route.tera"
layout = "layout.tera"

[features]
# Template features
i18n = true
components = true
routing = true
"#;

    let manifest_path = format!("{}/manifest.toml", dist_dir);
    std::fs::write(manifest_path, manifest_content)?;
    println!("  📄 Template manifest created");

    Ok(())
}

/// Create unified template manifest for all template types
fn create_unified_template_manifest(dist_dir: &str) -> Result<()> {
    let manifest_content = r#"[package]
name = "rustelo-templates-unified"
version = "0.1.0"
description = "Rustelo framework unified template collection"
authors = ["Rustelo Team"]
architecture = "unified"

[template-types]
project = "Complete project scaffolding with tooling"
crates = "Trait-based crate customization templates"
features = "Feature-specific configuration templates"

[project-templates]
# Full project templates
basic = "Standard web application template"
cms = "Content management focused template"
minimal = "Lightweight template for prototypes"
enterprise = "Advanced features for large deployments"
saas = "Software-as-a-Service template"
ai-powered = "AI/ML integration template"
ecommerce = "Online store functionality template"

[crate-templates]
# Individual crate templates for customization
client-template = "WASM client with trait-based routing"
server-template = "Axum server with comprehensive features"
core-lib-template = "Core business logic implementations"
rustelo-cli = "CLI tool template"

[feature-templates]
# Feature-specific configuration templates
analytics = "Analytics configuration and tracking"
smart-build = "Build optimization and caching"
debugging-tools = "Enhanced debugging capabilities"

[capabilities]
# Template system capabilities
variable-substitution = true
workspace-integration = true
trait-based-customization = true
layered-overrides = true
feature-composition = true
framework-integrity-protection = true

[workflow]
# Supported workflows
project-creation = "cargo rustelo new <project> --template <type>"
crate-customization = "cargo rustelo clone <crate> --target local-crates"
feature-management = "cargo rustelo add/remove <feature>"
system-updates = "cargo rustelo update (preserves customizations)"
"#;

    let manifest_path = format!("{}/manifest.toml", dist_dir);
    std::fs::write(manifest_path, manifest_content)?;
    println!("  📄 Unified template manifest created");

    Ok(())
}

/// Create default Dockerfile
fn create_default_dockerfile() -> Result<()> {
    let dockerfile_content = r#"FROM rust:1.75 as builder

WORKDIR /app
COPY . .
RUN cargo build --release --bin tools

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/target/release/tools /usr/local/bin/tools

CMD ["tools", "--help"]
"#;

    std::fs::write("Dockerfile", dockerfile_content)?;
    println!("  🐳 Default Dockerfile created");

    Ok(())
}
