//! Shared helpers for building Kubernetes child resources as JSON objects.

use crate::crd::{EnvVar, K8sObjectMeta, OwnerReference};

/// Query a Deployment's actual status and derive the CR's phase.
pub async fn query_deployment_status(
    client: &kube::Client,
    ns: &str,
    name: &str,
) -> Result<(i32, String), kube::Error> {
    use k8s_openapi::api::apps::v1::Deployment;

    let api: kube::Api<Deployment> = kube::Api::namespaced(client.clone(), ns);
    match api.get(name).await {
        Ok(d) => {
            let ready = d.status.as_ref().and_then(|s| s.ready_replicas).unwrap_or(0);
            let phase = if ready > 0 { "Running" } else { "Pending" };
            Ok((ready, phase.to_string()))
        }
        Err(kube::Error::Api(e)) if e.code == 404 => Ok((0, "Pending".to_string())),
        Err(e) => Err(e),
    }
}

/// Labels applied to every child resource.
pub fn std_labels() -> std::collections::BTreeMap<String, String> {
    let mut m = std::collections::BTreeMap::new();
    m.insert(
        "app.kubernetes.io/managed-by".to_string(),
        "code-operator".to_string(),
    );
    m.insert(
        "app.kubernetes.io/part-of".to_string(),
        "code-system".to_string(),
    );
    m
}

pub fn child_meta(
    name: &str,
    namespace: &str,
    owner: &OwnerReference,
    labels: std::collections::BTreeMap<String, String>,
) -> K8sObjectMeta {
    K8sObjectMeta {
        name: Some(name.to_string()),
        namespace: Some(namespace.to_string()),
        labels: Some(labels),
        owner_references: Some(vec![owner.clone().into()]),
        ..Default::default()
    }
}

pub fn owner_ref(parent: &K8sObjectMeta, api_version: &str, kind: &str) -> OwnerReference {
    OwnerReference {
        api_version: api_version.to_string(),
        kind: kind.to_string(),
        name: parent.name.clone().unwrap_or_default(),
        uid: parent.uid.clone().unwrap_or_default(),
        controller: Some(true),
        block_owner_deletion: Some(true),
    }
}

/// Merge env vars (global first, then local overrides).
pub fn merge_env(global: &[EnvVar], local: &[EnvVar]) -> Vec<EnvVar> {
    use std::collections::BTreeMap;
    let mut map: BTreeMap<String, EnvVar> = global
        .iter()
        .cloned()
        .map(|e| (e.name.clone(), e))
        .collect();
    for e in local {
        map.insert(e.name.clone(), e.clone());
    }
    map.into_values().collect()
}

pub fn env_var_to_json(e: &EnvVar) -> serde_json::Value {
    use serde_json::json;
    let mut m = json!({ "name": e.name });
    if let Some(ref v) = e.value {
        m["value"] = json!(v);
    }
    if let Some(ref src) = e.value_from {
        if let Some(ref sr) = src.secret_ref {
            m["valueFrom"] = json!({
                "secretRef": {
                    "name": sr.secret_name,
                    "key": sr.secret_key,
                }
            });
        }
    }
    m
}
