use std::{collections::HashMap, path::PathBuf};

use crate::config::ServiceDefinition;

/// Builder for daemon installation metadata.
///
/// This struct describes the daemon to be installed, including its executable path,
/// arguments, environment variables, and service configuration.
#[derive(Debug, Clone)]
pub struct InstallerBuilder {
    /// Service identifier (systemd unit name, launchd label, Windows service name)
    pub label: String,

    /// Path to the daemon executable
    pub program: PathBuf,

    /// Command line arguments for the daemon
    pub args: Vec<String>,

    /// Environment variables to set for the daemon process
    pub env: HashMap<String, String>,

    /// User account to run the daemon as
    pub run_as_user: String,

    /// Group to run the daemon as (Unix only)
    pub run_as_group: String,

    /// Human-readable description of the service
    pub description: String,

    /// Whether to automatically restart on failure
    pub auto_restart: bool,

    /// Whether the daemon requires network availability
    pub wants_network: bool,

    /// Service definitions to install with the daemon
    pub services: Vec<ServiceDefinition>,

    /// Whether to start service automatically after installation
    pub auto_start: bool,
}

impl InstallerBuilder {
    /// Create a new installer configuration.
    ///
    /// # Arguments
    ///
    /// * `label` - Unique identifier for the service (e.g., "my-daemon")
    /// * `program` - Path to the daemon executable
    pub fn new(label: &str, program: impl Into<PathBuf>) -> Self {
        Self {
            label: label.to_string(),
            program: program.into(),
            args: Vec::new(),
            env: HashMap::new(),
            run_as_user: "daemon".into(),
            run_as_group: "daemon".into(),
            description: format!("{label} service"),
            auto_restart: true,
            wants_network: true,
            services: Vec::new(),
            auto_start: true,
        }
    }

    /// Add multiple command line arguments.
    pub fn args<I, S>(mut self, args: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: Into<String>,
    {
        self.args.extend(args.into_iter().map(Into::into));
        self
    }

    /// Set an environment variable.
    pub fn env(mut self, k: impl Into<String>, v: impl Into<String>) -> Self {
        self.env.insert(k.into(), v.into());
        self
    }

    /// Set the user account to run as.
    pub fn user(mut self, u: impl Into<String>) -> Self {
        self.run_as_user = u.into();
        self
    }

    /// Set the group to run as (Unix only).
    pub fn group(mut self, g: impl Into<String>) -> Self {
        self.run_as_group = g.into();
        self
    }

    /// Set the service description.
    pub fn description(mut self, d: impl Into<String>) -> Self {
        self.description = d.into();
        self
    }

    /// Enable or disable automatic restart on failure.
    pub fn auto_restart(mut self, v: bool) -> Self {
        self.auto_restart = v;
        self
    }

    /// Specify whether the daemon requires network availability.
    pub fn network(mut self, v: bool) -> Self {
        self.wants_network = v;
        self
    }

    /// Add a service definition to install with the daemon.
    pub fn service(self, service: ServiceDefinition) -> Self {
        let mut services = self.services;
        services.push(service);
        Self { services, ..self }
    }

    /// Set whether to start service automatically after installation.
    pub fn auto_start(mut self, auto_start: bool) -> Self {
        self.auto_start = auto_start;
        self
    }
}
