// Machine registry reads across the flat `~/.ccd/machines/` layout
// introduced by RFC 0006 M1 and the legacy `~/.ccd/pods/{pod}/` layout.
// Both layouts coexist during the pod-layer collapse; this module produces
// a deterministic union, fail-closed on malformed state.
//
// Validation discipline mirrors the active-identity path in
// `pod_identity::load_machine_manifest`: non-empty `machine.id`, valid
// machine-id syntax, non-empty profile entries, and for pod-scoped
// manifests, every profile listed must be owned by the sibling `pod.toml`.

use std::collections::{BTreeMap, BTreeSet};
use std::fs;
use std::path::{Path, PathBuf};

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

use crate::paths::state::{
    validate_machine_id, validate_pod_name, ResolvedCoordinationScope, StateLayout,
};

#[derive(Debug, Clone, Serialize)]
pub(crate) struct MachineRecord {
    pub id: String,
    pub display_name: Option<String>,
    pub trust_class: MachineTrustClass,
    pub profiles: Vec<String>,
    pub capabilities: Vec<String>,
    pub source: MachineSource,
    pub pod_name: Option<String>,
    pub manifest_path: String,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum MachineSource {
    Flat,
    PodScoped,
}

impl MachineSource {
    pub(crate) fn as_str(self) -> &'static str {
        match self {
            Self::Flat => "flat",
            Self::PodScoped => "pod_scoped",
        }
    }
}

#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
struct MachineManifestFile {
    machine: MachineSection,
}

#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct MachineSection {
    id: String,
    display_name: Option<String>,
    trust_class: MachineTrustClass,
    profiles: Vec<String>,
    capabilities: Vec<String>,
}

/// Read every machine manifest under `~/.ccd/machines/` and
/// `~/.ccd/pods/{pod}/` (or the `ccd_root` override). Fails closed on
/// malformed manifests or same-layout duplicate ids. Cross-layout
/// precedence is explicit and deterministic: flat-layout records win
/// when the same id appears under both layouts, and the pod-scoped copy
/// is silently dropped from the output.
pub(crate) fn load_all_machines(ccd_root: &Path) -> Result<Vec<MachineRecord>> {
    let mut seen: BTreeSet<String> = BTreeSet::new();
    let mut records = Vec::new();

    for record in load_flat_machines(ccd_root)? {
        if seen.insert(record.id.clone()) {
            records.push(record);
        }
    }

    for record in load_pod_scoped_machines(ccd_root)? {
        if seen.insert(record.id.clone()) {
            records.push(record);
        }
    }

    records.sort_by(|a, b| a.id.cmp(&b.id));
    Ok(records)
}

fn load_flat_machines(ccd_root: &Path) -> Result<Vec<MachineRecord>> {
    let root = ccd_root.join("machines");
    let entries = read_dir_sorted(&root)?;

    let mut records: Vec<MachineRecord> = Vec::new();
    let mut seen: BTreeMap<String, PathBuf> = BTreeMap::new();

    for entry in entries {
        if !entry.file_type()?.is_dir() {
            continue;
        }
        let manifest_path = entry.path().join("machine.toml");
        // `presence/` and any other directory without a `machine.toml` is
        // skipped so the presence subtree can coexist with identity dirs
        // under the same root.
        if !manifest_path.is_file() {
            continue;
        }
        let record = load_manifest(&manifest_path, MachineSource::Flat, None, None)?;
        if let Some(existing) = seen.get(&record.id) {
            bail!(
                "duplicate machine id `{}` in flat layout: {} and {}",
                record.id,
                existing.display(),
                manifest_path.display()
            );
        }
        seen.insert(record.id.clone(), manifest_path.clone());
        records.push(record);
    }

    Ok(records)
}

fn load_pod_scoped_machines(ccd_root: &Path) -> Result<Vec<MachineRecord>> {
    let pods_root = ccd_root.join("pods");
    let entries = read_dir_sorted(&pods_root)?;

    let mut records: Vec<MachineRecord> = Vec::new();
    let mut seen: BTreeMap<String, PathBuf> = BTreeMap::new();

    for entry in entries {
        if !entry.file_type()?.is_dir() {
            continue;
        }
        let pod_dir = entry.path();
        let Some(pod_name) = pod_dir
            .file_name()
            .and_then(|segment| segment.to_str())
            .map(String::from)
        else {
            continue;
        };
        let manifest_path = pod_dir.join("machine.toml");
        if !manifest_path.is_file() {
            continue;
        }
        // A pod directory without a valid pod.toml is not a real pod;
        // skip its machine.toml so we never surface an unauthorized
        // record. A parse error on pod.toml is still a hard failure.
        let Some(owned_profiles) = load_pod_owned_profiles(&pod_dir)? else {
            continue;
        };

        let record = load_manifest(
            &manifest_path,
            MachineSource::PodScoped,
            Some(pod_name.clone()),
            Some(&owned_profiles),
        )?;
        if let Some(existing) = seen.get(&record.id) {
            bail!(
                "duplicate machine id `{}` in pod-scoped layout: {} and {}",
                record.id,
                existing.display(),
                manifest_path.display()
            );
        }
        seen.insert(record.id.clone(), manifest_path.clone());
        records.push(record);
    }

    Ok(records)
}

fn load_manifest(
    manifest_path: &Path,
    source: MachineSource,
    pod_name: Option<String>,
    owned_profiles: Option<&BTreeSet<String>>,
) -> Result<MachineRecord> {
    let raw = fs::read_to_string(manifest_path)
        .with_context(|| format!("failed to read {}", manifest_path.display()))?;
    let manifest: MachineManifestFile = toml::from_str(&raw)
        .with_context(|| format!("failed to parse {}", manifest_path.display()))?;

    if manifest.machine.id.trim().is_empty() {
        bail!(
            "{} must declare a non-empty machine.id",
            manifest_path.display()
        );
    }
    validate_machine_id(&manifest.machine.id)?;

    for profile in &manifest.machine.profiles {
        if profile.trim().is_empty() {
            bail!(
                "{} contains an empty profile entry in machine.profiles",
                manifest_path.display()
            );
        }
        if let Some(owned) = owned_profiles {
            if !owned.contains(profile) {
                bail!(
                    "{} declares machine profile `{profile}` that is not owned by pod `{}`",
                    manifest_path.display(),
                    pod_name.as_deref().unwrap_or("<unknown>")
                );
            }
        }
    }

    Ok(MachineRecord {
        id: manifest.machine.id,
        display_name: manifest.machine.display_name,
        trust_class: manifest.machine.trust_class,
        profiles: manifest.machine.profiles,
        capabilities: manifest.machine.capabilities,
        source,
        pod_name,
        manifest_path: manifest_path.display().to_string(),
    })
}

/// Parse a `pod.toml` just enough to expose the owned-profile set.
///
/// Returns `Ok(None)` when the pod directory has no `pod.toml` — such a
/// directory is not a real pod and should be skipped. Parse errors and
/// missing `[pod].name` are hard failures so malformed pods cannot
/// silently suppress the ownership check.
fn load_pod_owned_profiles(pod_dir: &Path) -> Result<Option<BTreeSet<String>>> {
    let pod_toml = pod_dir.join("pod.toml");
    if !pod_toml.is_file() {
        return Ok(None);
    }
    let raw = fs::read_to_string(&pod_toml)
        .with_context(|| format!("failed to read {}", pod_toml.display()))?;
    let value: toml::Value =
        toml::from_str(&raw).with_context(|| format!("failed to parse {}", pod_toml.display()))?;

    value
        .get("pod")
        .and_then(|section| section.get("name"))
        .and_then(|name| name.as_str())
        .ok_or_else(|| anyhow::anyhow!("{} must declare [pod].name", pod_toml.display()))?;

    let owned: BTreeSet<String> = value
        .get("profiles")
        .and_then(|section| section.as_table())
        .map(|table| table.keys().cloned().collect())
        .unwrap_or_default();

    Ok(Some(owned))
}

fn read_dir_sorted(root: &Path) -> Result<Vec<fs::DirEntry>> {
    let Ok(iter) = fs::read_dir(root) else {
        return Ok(Vec::new());
    };
    let mut entries: Vec<fs::DirEntry> = iter.collect::<std::io::Result<Vec<_>>>()?;
    entries.sort_by_key(|entry| entry.file_name());
    Ok(entries)
}

#[derive(Debug, Clone)]
pub(crate) struct LoadedPodIdentity {
    pub name: String,
    pub manifest_path: PathBuf,
    pub policy_path: PathBuf,
    pub owned_profiles: Vec<String>,
}

#[derive(Debug, Clone, Serialize)]
pub(crate) struct CoordinationScopeView {
    pub status: &'static str,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source: Option<&'static str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub config_path: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub shared_root: Option<String>,
}

#[derive(Debug, Clone)]
pub(crate) struct LoadedMachineIdentity {
    pub id: String,
    pub display_name: Option<String>,
    pub manifest_path: PathBuf,
    pub trust_class: MachineTrustClass,
    pub available_profiles: Vec<String>,
    pub capabilities: Vec<String>,
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum MachineTrustClass {
    #[default]
    Owned,
    Limited,
    Observer,
}

#[derive(Debug, Clone, Serialize)]
pub(crate) struct MachineIdentityView {
    pub status: &'static str,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub display_name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub manifest_path: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub trust_class: Option<MachineTrustClass>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub available_profiles: Vec<String>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub capabilities: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
struct PodManifestFile {
    pod: PodSection,
    #[serde(default)]
    profiles: BTreeMap<String, PodProfileSection>,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
struct PodSection {
    name: String,
    // Parsed for legacy `pod.toml` compat (pod layer is retiring per RFC 0006);
    // the value is discarded because no surviving surface displays it.
    #[serde(default)]
    #[allow(dead_code)]
    display_name: Option<String>,
}

#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct PodProfileSection {
    description: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
struct PodScopedMachineManifestFile {
    machine: PodScopedMachineSection,
}

#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, deny_unknown_fields)]
struct PodScopedMachineSection {
    id: String,
    display_name: Option<String>,
    trust_class: MachineTrustClass,
    profiles: Vec<String>,
    capabilities: Vec<String>,
}

pub(crate) fn resolve_active_identity(layout: &StateLayout) -> Result<Option<LoadedPodIdentity>> {
    let profile_name = layout.profile().as_str();
    let mut matches = Vec::new();

    for manifest in load_all_manifests(layout)? {
        if manifest
            .owned_profiles
            .iter()
            .any(|owned| owned == profile_name)
        {
            matches.push(manifest);
        }
    }

    if matches.len() > 1 {
        let owners = matches
            .iter()
            .map(|identity| identity.name.clone())
            .collect::<Vec<_>>()
            .join(", ");
        bail!(
            "profile `{profile_name}` is claimed by multiple pod identities ({owners}); edit the conflicting `pod.toml` files so one profile belongs to only one pod"
        );
    }

    Ok(matches.into_iter().next())
}

pub(crate) fn resolve_coordination_scope_view(
    layout: &StateLayout,
    locality_id: &str,
) -> Result<CoordinationScopeView> {
    let resolved = layout.resolved_coordination_scope(locality_id)?;
    Ok(coordination_scope_view_from(resolved.as_ref()))
}

pub(crate) fn resolve_active_machine_identity(
    layout: &StateLayout,
) -> Result<Option<LoadedMachineIdentity>> {
    let Some(identity) = resolve_active_identity(layout)? else {
        return Ok(None);
    };

    let manifest_path = layout.pod_machine_manifest_path(&identity.name)?;
    if !manifest_path.is_file() {
        return Ok(None);
    }

    Ok(Some(load_pod_machine_manifest(&identity, &manifest_path)?))
}

pub(crate) fn resolve_machine_identity_view(layout: &StateLayout) -> Result<MachineIdentityView> {
    let active_pod = resolve_active_identity(layout)?;
    let active_machine = active_pod
        .as_ref()
        .map(|_| resolve_active_machine_identity(layout))
        .transpose()?
        .flatten();
    machine_identity_view_from(active_pod.as_ref(), active_machine.as_ref(), layout)
}

fn load_all_manifests(layout: &StateLayout) -> Result<Vec<LoadedPodIdentity>> {
    let pods_root = layout.ccd_root().join("pods");
    let Ok(entries) = fs::read_dir(&pods_root) else {
        return Ok(Vec::new());
    };

    let mut manifests = Vec::new();
    for entry in entries {
        let entry = entry?;
        if !entry.file_type()?.is_dir() {
            continue;
        }

        let pod_dir = entry.path();
        let manifest_path = pod_dir.join("pod.toml");
        if !manifest_path.is_file() {
            continue;
        }

        manifests.push(load_pod_manifest(&pod_dir, &manifest_path)?);
    }

    Ok(manifests)
}

fn load_pod_manifest(pod_dir: &Path, manifest_path: &Path) -> Result<LoadedPodIdentity> {
    let raw = fs::read_to_string(manifest_path)
        .with_context(|| format!("failed to read {}", manifest_path.display()))?;
    let manifest: PodManifestFile = toml::from_str(&raw)
        .with_context(|| format!("failed to parse {}", manifest_path.display()))?;

    if manifest.profiles.is_empty() {
        bail!(
            "{} must declare at least one owned profile under [profiles]",
            manifest_path.display()
        );
    }

    let dir_name = pod_dir
        .file_name()
        .and_then(|segment| segment.to_str())
        .ok_or_else(|| anyhow::anyhow!("invalid pod directory name for {}", pod_dir.display()))?;

    validate_pod_name(&manifest.pod.name)?;
    if manifest.pod.name != dir_name {
        bail!(
            "{} declares pod name `{}` but lives under `pods/{dir_name}`; keep the manifest name aligned with its directory",
            manifest_path.display(),
            manifest.pod.name
        );
    }

    let owned_profiles = manifest
        .profiles
        .into_keys()
        .map(|name| {
            if name.trim().is_empty() {
                bail!(
                    "{} contains an empty profile key under [profiles]",
                    manifest_path.display()
                );
            }
            Ok(name)
        })
        .collect::<Result<Vec<_>>>()?;

    let policy_path = pod_dir.join("policy.md");

    Ok(LoadedPodIdentity {
        name: manifest.pod.name,
        manifest_path: manifest_path.to_path_buf(),
        policy_path,
        owned_profiles,
    })
}

fn load_pod_machine_manifest(
    pod_identity: &LoadedPodIdentity,
    manifest_path: &Path,
) -> Result<LoadedMachineIdentity> {
    let raw = fs::read_to_string(manifest_path)
        .with_context(|| format!("failed to read {}", manifest_path.display()))?;
    let manifest: PodScopedMachineManifestFile = toml::from_str(&raw)
        .with_context(|| format!("failed to parse {}", manifest_path.display()))?;

    crate::paths::state::validate_machine_id(&manifest.machine.id)?;
    if manifest.machine.id.trim().is_empty() {
        bail!(
            "{} must declare a non-empty machine.id",
            manifest_path.display()
        );
    }

    for profile in &manifest.machine.profiles {
        if profile.trim().is_empty() {
            bail!(
                "{} contains an empty profile entry in machine.profiles",
                manifest_path.display()
            );
        }
        if !pod_identity
            .owned_profiles
            .iter()
            .any(|owned| owned == profile)
        {
            bail!(
                "{} declares machine profile `{profile}` that is not owned by pod `{}`",
                manifest_path.display(),
                pod_identity.name
            );
        }
    }

    Ok(LoadedMachineIdentity {
        id: manifest.machine.id,
        display_name: manifest.machine.display_name,
        manifest_path: manifest_path.to_path_buf(),
        trust_class: manifest.machine.trust_class,
        available_profiles: manifest.machine.profiles,
        capabilities: manifest.machine.capabilities,
    })
}

fn machine_identity_view_from(
    pod_identity: Option<&LoadedPodIdentity>,
    machine_identity: Option<&LoadedMachineIdentity>,
    layout: &StateLayout,
) -> Result<MachineIdentityView> {
    match machine_identity {
        Some(identity) => Ok(MachineIdentityView {
            status: "declared",
            id: Some(identity.id.clone()),
            display_name: identity.display_name.clone(),
            manifest_path: Some(identity.manifest_path.display().to_string()),
            trust_class: Some(identity.trust_class),
            available_profiles: identity.available_profiles.clone(),
            capabilities: identity.capabilities.clone(),
            reason: None,
        }),
        None => Ok(MachineIdentityView {
            status: "missing",
            id: None,
            display_name: None,
            manifest_path: pod_identity
                .map(|identity| layout.pod_machine_manifest_path(&identity.name))
                .transpose()?
                .map(|path| path.display().to_string()),
            trust_class: None,
            available_profiles: Vec::new(),
            capabilities: Vec::new(),
            reason: pod_identity.map(|_| {
                format!(
                    "machine identity is optional for profile/worktree-local workflows; no active machine identity is declared for profile `{}`",
                    layout.profile()
                )
            }),
        }),
    }
}

fn coordination_scope_view_from(
    scope: Option<&ResolvedCoordinationScope>,
) -> CoordinationScopeView {
    match scope {
        Some(scope) => CoordinationScopeView {
            status: "configured",
            name: Some(scope.name.clone()),
            source: Some(scope.source.as_str()),
            config_path: Some(scope.config_path.display().to_string()),
            shared_root: Some(scope.shared_root.display().to_string()),
        },
        None => CoordinationScopeView {
            status: "missing",
            name: None,
            source: None,
            config_path: None,
            shared_root: None,
        },
    }
}

#[cfg(test)]
mod tests {
    use std::fs;

    use tempfile::tempdir;

    use super::*;

    fn write(path: &std::path::Path, body: &str) {
        fs::create_dir_all(path.parent().unwrap()).unwrap();
        fs::write(path, body).unwrap();
    }

    fn operator_pod_toml() -> &'static str {
        r#"[pod]
name = "operator"

[profiles]
main = { description = "Primary profile" }
"#
    }

    const FLAT_MANIFEST: &str = r#"[machine]
id = "laptop-amsterdam"
display_name = "Operator Laptop"
trust_class = "owned"
profiles = ["main"]
capabilities = ["git", "cargo"]
"#;

    const POD_MANIFEST: &str = r#"[machine]
id = "desktop-tokyo"
display_name = "Operator Desktop"
trust_class = "limited"
profiles = ["main"]
capabilities = ["docker"]
"#;

    #[test]
    fn returns_empty_when_no_layout_exists() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        let records = load_all_machines(&ccd_root).unwrap();
        assert!(records.is_empty());
    }

    #[test]
    fn reads_flat_layout_only() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/laptop-amsterdam/machine.toml"),
            FLAT_MANIFEST,
        );
        let records = load_all_machines(&ccd_root).unwrap();
        assert_eq!(records.len(), 1);
        assert_eq!(records[0].id, "laptop-amsterdam");
        assert_eq!(records[0].source, MachineSource::Flat);
        assert!(records[0].pod_name.is_none());
    }

    #[test]
    fn reads_pod_scoped_layout_only() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("pods/operator/pod.toml"),
            operator_pod_toml(),
        );
        write(&ccd_root.join("pods/operator/machine.toml"), POD_MANIFEST);
        let records = load_all_machines(&ccd_root).unwrap();
        assert_eq!(records.len(), 1);
        assert_eq!(records[0].id, "desktop-tokyo");
        assert_eq!(records[0].source, MachineSource::PodScoped);
        assert_eq!(records[0].pod_name.as_deref(), Some("operator"));
    }

    #[test]
    fn merges_both_layouts_sorted_by_id() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/laptop-amsterdam/machine.toml"),
            FLAT_MANIFEST,
        );
        write(
            &ccd_root.join("pods/operator/pod.toml"),
            operator_pod_toml(),
        );
        write(&ccd_root.join("pods/operator/machine.toml"), POD_MANIFEST);
        let records = load_all_machines(&ccd_root).unwrap();
        assert_eq!(records.len(), 2);
        assert_eq!(records[0].id, "desktop-tokyo");
        assert_eq!(records[0].source, MachineSource::PodScoped);
        assert_eq!(records[1].id, "laptop-amsterdam");
        assert_eq!(records[1].source, MachineSource::Flat);
    }

    #[test]
    fn flat_layout_wins_on_cross_layout_id_collision() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/shared/machine.toml"),
            r#"[machine]
id = "shared"
trust_class = "owned"
profiles = ["main"]
"#,
        );
        write(
            &ccd_root.join("pods/operator/pod.toml"),
            operator_pod_toml(),
        );
        write(
            &ccd_root.join("pods/operator/machine.toml"),
            r#"[machine]
id = "shared"
trust_class = "limited"
profiles = ["main"]
"#,
        );
        let records = load_all_machines(&ccd_root).unwrap();
        assert_eq!(records.len(), 1);
        assert_eq!(records[0].source, MachineSource::Flat);
        assert_eq!(records[0].trust_class, MachineTrustClass::Owned);
    }

    #[test]
    fn skips_presence_subdir_in_flat_layout() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/laptop-amsterdam/machine.toml"),
            FLAT_MANIFEST,
        );
        write(
            &ccd_root.join("machines/presence/laptop-amsterdam.json"),
            "{}",
        );
        let records = load_all_machines(&ccd_root).unwrap();
        assert_eq!(records.len(), 1);
        assert_eq!(records[0].id, "laptop-amsterdam");
    }

    #[test]
    fn skips_pod_dir_without_pod_toml() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        // machine.toml present but no pod.toml — not a real pod.
        write(&ccd_root.join("pods/ghost/machine.toml"), POD_MANIFEST);
        let records = load_all_machines(&ccd_root).unwrap();
        assert!(
            records.is_empty(),
            "pod dir without pod.toml must not surface machine records: {:?}",
            records
        );
    }

    #[test]
    fn rejects_empty_machine_id() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/bad/machine.toml"),
            r#"[machine]
id = ""
trust_class = "owned"
profiles = ["main"]
"#,
        );
        let err = load_all_machines(&ccd_root).expect_err("empty id must fail");
        let msg = format!("{err:#}");
        assert!(
            msg.contains("non-empty machine.id"),
            "expected non-empty machine.id error, got: {msg}"
        );
    }

    #[test]
    fn rejects_whitespace_only_machine_id() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/bad/machine.toml"),
            "[machine]\nid = \"   \"\ntrust_class = \"owned\"\nprofiles = [\"main\"]\n",
        );
        let err = load_all_machines(&ccd_root).expect_err("whitespace id must fail");
        assert!(format!("{err:#}").contains("non-empty machine.id"));
    }

    #[test]
    fn rejects_empty_profile_entry() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/laptop/machine.toml"),
            r#"[machine]
id = "laptop"
trust_class = "owned"
profiles = ["main", ""]
"#,
        );
        let err = load_all_machines(&ccd_root).expect_err("empty profile entry must fail");
        assert!(format!("{err:#}").contains("empty profile entry"));
    }

    #[test]
    fn rejects_duplicate_flat_layout_ids() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("machines/alpha/machine.toml"),
            r#"[machine]
id = "same"
trust_class = "owned"
profiles = ["main"]
"#,
        );
        write(
            &ccd_root.join("machines/beta/machine.toml"),
            r#"[machine]
id = "same"
trust_class = "owned"
profiles = ["main"]
"#,
        );
        let err = load_all_machines(&ccd_root).expect_err("duplicate flat id must fail");
        let msg = format!("{err:#}");
        assert!(msg.contains("duplicate machine id `same`"));
        assert!(msg.contains("machines/alpha/machine.toml"));
        assert!(msg.contains("machines/beta/machine.toml"));
    }

    #[test]
    fn rejects_duplicate_pod_scoped_ids() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(&ccd_root.join("pods/podA/pod.toml"), operator_pod_toml());
        write(&ccd_root.join("pods/podB/pod.toml"), operator_pod_toml());
        write(
            &ccd_root.join("pods/podA/machine.toml"),
            r#"[machine]
id = "same"
trust_class = "owned"
profiles = ["main"]
"#,
        );
        write(
            &ccd_root.join("pods/podB/machine.toml"),
            r#"[machine]
id = "same"
trust_class = "limited"
profiles = ["main"]
"#,
        );
        let err = load_all_machines(&ccd_root).expect_err("duplicate pod id must fail");
        let msg = format!("{err:#}");
        assert!(msg.contains("duplicate machine id `same`"));
        assert!(msg.contains("pods/podA/machine.toml"));
        assert!(msg.contains("pods/podB/machine.toml"));
    }

    #[test]
    fn rejects_pod_scoped_profile_not_owned_by_pod() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("pods/operator/pod.toml"),
            operator_pod_toml(),
        );
        write(
            &ccd_root.join("pods/operator/machine.toml"),
            r#"[machine]
id = "laptop"
trust_class = "owned"
profiles = ["not-owned"]
"#,
        );
        let err = load_all_machines(&ccd_root).expect_err("unowned profile must fail");
        let msg = format!("{err:#}");
        assert!(msg.contains("not owned by pod `operator`"), "got: {msg}");
    }

    #[test]
    fn rejects_invalid_pod_toml() {
        let temp = tempdir().unwrap();
        let ccd_root = temp.path().join(".ccd");
        write(
            &ccd_root.join("pods/broken/pod.toml"),
            "this is not toml ===",
        );
        write(&ccd_root.join("pods/broken/machine.toml"), POD_MANIFEST);
        let err = load_all_machines(&ccd_root).expect_err("parse error must fail");
        assert!(format!("{err:#}").contains("failed to parse"));
    }
}
