//! Builder pattern for complex benchmark operations

use super::error::ProfilingError;
use super::report::builder::BenchmarkReport;
use std::path::PathBuf;
use std::time::Duration;

/// Builder for configuring and running comprehensive benchmarks
#[derive(Debug, Clone)]
pub struct BenchmarkBuilder {
    disk_path: Option<PathBuf>,
    duration: Option<Duration>,
    include_cpu: bool,
    include_memory: bool,
    include_disk: bool,
    include_network: bool,
    network_server: Option<String>,
}

impl Default for BenchmarkBuilder {
    fn default() -> Self {
        Self {
            disk_path: None,
            duration: Some(Duration::from_secs(30)),
            include_cpu: true,
            include_memory: true,
            include_disk: true,
            include_network: true,
            network_server: None,
        }
    }
}

impl BenchmarkBuilder {
    /// Create a new benchmark builder with default settings
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the disk path for disk benchmarks
    pub fn with_disk_path<P: AsRef<std::path::Path>>(mut self, path: P) -> Self {
        self.disk_path = Some(path.as_ref().to_path_buf());
        self
    }

    /// Set the duration for benchmarks
    pub fn with_duration(mut self, duration: Duration) -> Self {
        self.duration = Some(duration);
        self
    }

    /// Include or exclude CPU benchmarks
    pub fn with_cpu(mut self, include: bool) -> Self {
        self.include_cpu = include;
        self
    }

    /// Include or exclude memory benchmarks
    pub fn with_memory(mut self, include: bool) -> Self {
        self.include_memory = include;
        self
    }

    /// Include or exclude disk benchmarks
    pub fn with_disk(mut self, include: bool) -> Self {
        self.include_disk = include;
        self
    }

    /// Include or exclude network benchmarks
    pub fn with_network(mut self, include: bool) -> Self {
        self.include_network = include;
        self
    }

    /// Set network server for bandwidth tests
    pub fn with_network_server<S: Into<String>>(mut self, server: S) -> Self {
        self.network_server = Some(server.into());
        self
    }

    /// Run the configured benchmark and return a populated report
    pub fn run(self) -> Result<BenchmarkReport, ProfilingError> {
        let mut report = BenchmarkReport::new();

        // Set system profile
        report.set_system_profile(super::system::SystemProfile::detect()?);

        // Run CPU benchmarks if enabled
        if self.include_cpu {
            super::logging::log_info("Running CPU benchmark");
            let cpu_result = {
                let profiler = super::cpu::profiler::CPUProfiler::new();
                profiler.run_benchmark(
                    4, // threads
                    self.duration.unwrap_or(Duration::from_secs(30)),
                )?
            };
            report.add_cpu_result(cpu_result)?;
        }

        // Run memory benchmarks if enabled
        if self.include_memory {
            super::logging::log_info("Running memory benchmark");
            let memory_result = super::memory::bandwidth::measure_memory_bandwidth()?;
            report.add_memory_result(memory_result)?;
        }

        // Run disk benchmarks if enabled and path is provided
        if self.include_disk {
            if let Some(disk_path) = &self.disk_path {
                super::logging::log_info(&format!("Running disk benchmark on {:?}", disk_path));
                let disk_result = super::disk::profiler::run_disk_benchmark(disk_path)?;
                report.add_disk_result(disk_result)?;
            } else {
                super::logging::log_warn("Disk benchmarks skipped: no disk path provided");
            }
        }

        // Run network benchmarks if enabled
        if self.include_network {
            super::logging::log_info("Running network benchmark");

            // Always run latency test
            let latency_result = super::network::latency::measure_latency("localhost", 5)?;
            report.add_network_result(latency_result.into())?;

            // Run bandwidth test if server is provided
            if let Some(server) = &self.network_server {
                let bandwidth_result = super::network::bandwidth::measure_bandwidth(
                    server,
                    self.duration.unwrap_or(Duration::from_secs(10)),
                )?;
                report.add_network_result(bandwidth_result.into())?;
            }
        }

        Ok(report)
    }
}
