use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};

use crate::settings::run::RunMode;

/// Sandbox provider discriminator for agent tool operations.
#[derive(
    Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, Display, EnumString,
)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase", ascii_case_insensitive)]
pub enum SandboxProviderKind {
    /// Run tools on the local host.
    #[default]
    Local,
    /// Run tools inside a Docker container.
    Docker,
    /// Run tools inside a Daytona cloud sandbox.
    Daytona,
}

impl SandboxProviderKind {
    /// True only for Local. Used by dry-run to force local execution.
    /// NOT the same as "runs on the host" (Docker is host-adjacent but not
    /// dry-run compatible).
    #[must_use]
    pub fn is_local(&self) -> bool {
        matches!(self, Self::Local)
    }

    /// True for providers that clone repository sources into their workspace.
    #[must_use]
    pub fn is_clone_based(&self) -> bool {
        matches!(self, Self::Docker | Self::Daytona)
    }

    /// Coerce non-local providers to `Local` under dry-run; otherwise
    /// unchanged.
    #[must_use]
    pub fn effective_for(self, mode: RunMode) -> Self {
        if mode == RunMode::DryRun && !self.is_local() {
            Self::Local
        } else {
            self
        }
    }
}

#[cfg(test)]
mod tests {
    use super::SandboxProviderKind;

    #[test]
    fn sandbox_provider_default_is_local() {
        assert_eq!(SandboxProviderKind::default(), SandboxProviderKind::Local);
    }

    #[test]
    fn sandbox_provider_from_str() {
        assert_eq!(
            "local".parse::<SandboxProviderKind>().unwrap(),
            SandboxProviderKind::Local
        );
        assert_eq!(
            "docker".parse::<SandboxProviderKind>().unwrap(),
            SandboxProviderKind::Docker
        );
        assert_eq!(
            "daytona".parse::<SandboxProviderKind>().unwrap(),
            SandboxProviderKind::Daytona
        );
        assert_eq!(
            "LOCAL".parse::<SandboxProviderKind>().unwrap(),
            SandboxProviderKind::Local
        );
        assert!("invalid".parse::<SandboxProviderKind>().is_err());
    }

    #[test]
    fn sandbox_provider_display() {
        assert_eq!(SandboxProviderKind::Local.to_string(), "local");
        assert_eq!(SandboxProviderKind::Docker.to_string(), "docker");
        assert_eq!(SandboxProviderKind::Daytona.to_string(), "daytona");
    }
}
