// Project:   scalo
// File:      src/deployment/generate/compose.rs
// Purpose:   Docker Compose fragment generation
// Language:  Rust
//
// License:   Apache-2.0
// Copyright: (c) 2026 HYPERI PTY LIMITED

#![allow(clippy::format_push_string)]

use crate::deployment::contract::DeploymentContract;

// ============================================================================
// Docker Compose fragment
// ============================================================================

/// Generate a Docker Compose service fragment from the deployment contract.
#[must_use]
pub fn generate_compose_fragment(contract: &DeploymentContract) -> String {
    let binary = contract.binary();
    let mut out = String::with_capacity(512);

    // Service definition
    out.push_str(&format!(
        "# Generated by scalo deployment module\nservices:\n  {}:\n",
        contract.app_name
    ));

    // Image
    out.push_str(&format!(
        "    image: {}/{}:${{{}_VERSION:-latest}}\n",
        contract.image_registry,
        contract.app_name,
        contract.env_prefix.replace("__", "_")
    ));

    // depends_on
    if !contract.depends_on.is_empty() {
        out.push_str("    depends_on:\n");
        for dep in &contract.depends_on {
            out.push_str(&format!(
                "      {dep}:\n        condition: service_healthy\n"
            ));
        }
    }

    // Ports
    out.push_str("    ports:\n");
    out.push_str(&format!(
        "      - \"{}:{}\"\n",
        contract.metrics_port, contract.metrics_port
    ));
    for p in &contract.extra_ports {
        out.push_str(&format!("      - \"{}:{}\"\n", p.port, p.port));
    }

    // Volumes -- config file mount
    out.push_str("    volumes:\n");
    out.push_str(&format!(
        "      - ./config/{}:{}:ro\n",
        contract.config_filename(),
        contract.config_mount_path,
    ));

    // Healthcheck
    out.push_str(&format!(
        "    healthcheck:\n\
         \x20     test: [\"CMD\", \"curl\", \"-sf\", \"http://localhost:{}{}\"]
      interval: 10s\n\
         \x20     timeout: 3s\n\
         \x20     retries: 5\n",
        contract.metrics_port, contract.health.liveness_path,
    ));

    // Entrypoint args
    if !contract.entrypoint_args.is_empty() {
        out.push_str(&format!("    command: [\"{binary}\""));
        for arg in &contract.entrypoint_args {
            out.push_str(&format!(", \"{arg}\""));
        }
        out.push_str("]\n");
    }

    out
}
