//! Worker Manager for managing worker process independently

use crate::config::ServerConfig;
use crate::control::ipc::{CommandResult, ControlCommand, WorkerSnapshot};
use crate::errors::{FalcornError, Result};
use crate::logging::logger::Logger;
use nix::sys::signal::{self, Signal};
use nix::unistd::Pid;
use std::collections::{HashMap, VecDeque};
use std::net::{SocketAddr, TcpListener};
use std::os::fd::AsRawFd;
use std::os::unix::process::CommandExt;
use std::process::{Child, Command};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;

/// Worker State
#[derive(Debug, Clone, PartialEq)]
pub enum WorkerState {
    Starting,
    Running,
    Stopping,
    Stopped,
    Failed,
}

/// Worker Process
pub struct WorkerProcess {
    pub id: u32,
    pub pid: Option<i32>,
    pub child: Option<Child>,
    pub state: WorkerState,
    pub restarts: u32,
    pub start_time: std::time::Instant,
    pub manual_stop: bool,
    pub pending_restart: bool,
}

#[derive(Debug, Default, Clone)]
pub struct WorkerSnapshotState {
    pub workers: Vec<WorkerSnapshot>,
}

impl WorkerProcess {
    fn new(id: u32) -> Self {
        Self {
            id,
            pid: None,
            child: None,
            state: WorkerState::Starting,
            restarts: 0,
            start_time: std::time::Instant::now(),
            manual_stop: false,
            pending_restart: false,
        }
    }
}

/// Multi-prrocess Worker manager
pub struct WorkerManager {
    config: Arc<Mutex<ServerConfig>>,
    logger: Arc<Logger>,
    workers: HashMap<u32, WorkerProcess>,
    shutdown: Arc<AtomicBool>,
    master_pid: i32,
    listener: Option<TcpListener>,
    snapshots: Arc<Mutex<WorkerSnapshotState>>,
    commands: Arc<Mutex<VecDeque<ControlCommand>>>,
    rolling_restart_queue: VecDeque<u32>,
}

impl WorkerManager {
    /// Create a new Worker Manager
    pub fn new(
        config: Arc<Mutex<ServerConfig>>,
        logger: Arc<Logger>,
        shutdown: Arc<AtomicBool>,
    ) -> Self {
        Self {
            config,
            logger,
            workers: HashMap::new(),
            shutdown: shutdown,
            master_pid: std::process::id() as i32,
            listener: None,
            snapshots: Arc::new(Mutex::new(WorkerSnapshotState::default())),
            commands: Arc::new(Mutex::new(VecDeque::new())),
            rolling_restart_queue: VecDeque::new(),
        }
    }

    pub fn snapshots(&self) -> Arc<Mutex<WorkerSnapshotState>> {
        Arc::clone(&self.snapshots)
    }

    pub fn commands(&self) -> Arc<Mutex<VecDeque<ControlCommand>>> {
        Arc::clone(&self.commands)
    }

    /// Create a TCP listener with SO_REUSEPORT
    fn create_listener(&self) -> Result<TcpListener> {
        use socket2::{Domain, Protocol, SockAddr, Socket, Type};
        // use std::os::unix::io::{FromRawFd, IntoRawFd};

        let config = self.config.lock().expect("config mutex poisoned").clone();
        let addr: SocketAddr = config
            .bind_addr()
            .parse()
            .map_err(|e| FalcornError::config(format!("Invalid bind address: {}", e)))?;

        // Domain option
        let domain = if addr.is_ipv4() {
            Domain::IPV4
        } else {
            Domain::IPV6
        };

        // Create a socket with SO_REUSEADDR and SO_REUSEPORT
        let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;

        // Activate SO_REUSEADDR
        socket
            .set_reuse_address(true)
            .map_err(|e| FalcornError::runtime(format!("Failed to set SO_REUSEADDR: {}", e)))?;

        // Activate SO_REUSEPORT
        socket
            .set_reuse_port(true)
            .map_err(|e| FalcornError::runtime(format!("Failed to set SO_REUSEPORT: {}", e)))?;

        // Non blocking
        socket.set_nonblocking(false)?;

        // Bind addr
        let sock_addr = SockAddr::from(addr);
        socket
            .bind(&sock_addr.into())
            .map_err(|e| FalcornError::runtime(format!("Failed to bind to {}: {}", addr, e)))?;

        // Now listen
        socket.listen(config.backlog as i32)?;

        let listener: std::net::TcpListener = socket.into();

        self.logger.debug(|| {
            format!(
                "[Master {}] Listening on {} (SO_REUSEPORT enabled)",
                self.master_pid,
                config.bind_addr()
            )
        });

        Ok(listener)
    }

    /// Spawn all workers
    pub fn spawn_workers(&mut self) -> Result<()> {
        // Creeate a TCP listener (reuse same port with SO_REUSEPORT)
        let listener = self.create_listener()?;
        self.listener = Some(listener);

        let config = self.config.lock().expect("config mutex poisoned").clone();
        self.logger.info(|| {
            format!(
                "[Master {}] Spawning {} worker processes",
                self.master_pid,
                config.worker_count()
            )
        });

        for i in 0..config.worker_count() {
            self.spawn_worker(i as u32)?;
        }

        Ok(())
    }

    /// Spawn a single worker
    fn spawn_worker(&mut self, id: u32) -> Result<()> {
        use nix::libc;
        let mut worker = WorkerProcess::new(id);

        let listen_fd = self.listener.as_ref().unwrap().as_raw_fd();
        let config = self.config.lock().expect("config mutex poisoned").clone();

        // Get curreent exe path
        let current_exe = std::env::current_exe()
            .map_err(|e| FalcornError::runtime(format!("Cannot get current exe: {}", e)))?;

        // Build cmd args for the worker
        let mut cmd = Command::new(&current_exe);

        cmd.arg("run")
            .arg(format!("{}:{}", config.app_module, config.app_callable))
            .arg("--host")
            .arg(config.host())
            .arg("--port")
            .arg(config.port().to_string())
            .arg("--backlog")
            .arg(config.backlog.to_string())
            .arg("--worker-id")
            .arg(id.to_string())
            .arg("--worker-mode")
            .arg("--protocol")
            .arg(config.protocol.as_str())
            .arg("--worker-class")
            .arg(config.worker_class.as_str())
            .arg("--timeout")
            .arg(config.worker_timeout.to_string())
            .arg("--buffer-size")
            .arg(config.buffer_size.to_string())
            .arg("--keepalive")
            .arg(config.keepalive_timeout.to_string())
            .arg("--max-connections")
            .arg(config.max_connections.to_string())
            .arg("--sync-handler-threads")
            .arg(config.sync_handler_threads.to_string())
            .arg("--sync-conn-queue-capacity")
            .arg(config.sync_conn_queue_capacity.to_string())
            .arg("--async-worker-threads")
            .arg(config.async_worker_threads.to_string())
            .arg("--async-max-blocking-threads")
            .arg(config.async_max_blocking_threads.to_string())
            .arg("--asgi-event-loop")
            .arg(config.asgi_event_loop.clone())
            .arg("--asgi-submit-timeout-ms")
            .arg(config.asgi_submit_timeout_ms.to_string())
            .arg("--asgi-scheduler")
            .arg(config.asgi_scheduler.clone())
            .arg("--asgi-max-inflight")
            .arg(config.asgi_max_inflight.to_string())
            .arg("--asgi-send-pool-size")
            .arg(config.asgi_send_pool_size.to_string())
            .arg("--log-level")
            .arg(config.log_level.to_string())
            .env("FALCORN_LISTEN_FD", listen_fd.to_string())
            .env("FALCORN_MASTER_PID", self.master_pid.to_string());

        if config.h2c_enabled {
            cmd.arg("--h2c");
        } else {
            cmd.arg("--no-h2c");
        }

        // Add python path if needed
        for path in &config.pythonpath {
            cmd.arg("--pythonpath").arg(path);
        }

        // max request
        if let Some(max_req) = config.max_requests {
            cmd.arg("--max-requests").arg(max_req.to_string());
        }
        if let Some(max_req_jitter) = config.max_requests_jitter {
            cmd.arg("--max-requests-jitter")
                .arg(max_req_jitter.to_string());
        }

        if config.asgi_event_loop_fallback {
            cmd.arg("--asgi-event-loop-fallback");
        } else {
            cmd.arg("--no-asgi-event-loop-fallback");
        }

        if config.log_stdout {
            cmd.arg("--log-stdout");
        } else {
            cmd.arg("--no-log-stdout");
        }
        if let Some(access_log) = &config.access_log {
            cmd.arg("--access-log").arg(access_log);
        }
        if let Some(error_log) = &config.error_log {
            cmd.arg("--error-log").arg(error_log);
        }
        cmd.arg("--access-log-format")
            .arg(config.access_log_format.clone());

        if config.ssl_enabled {
            cmd.arg("--ssl-enabled");
        } else {
            cmd.arg("--no-ssl-enabled");
        }
        if let Some(certfile) = &config.ssl_certfile {
            cmd.arg("--ssl-certfile").arg(certfile);
        }
        if let Some(keyfile) = &config.ssl_keyfile {
            cmd.arg("--ssl-keyfile").arg(keyfile);
        }

        // Enable/Disable Plugin Events dispatch
        if let Some(plugin_socket) = &config.plugin_socket {
            cmd.arg("--plugin-socket").arg(plugin_socket);
        }

        // Metrics
        // Interval
        cmd.arg("--metrics-interval-ms")
            .arg(config.metrics_interval_ms.to_string());

        // OS
        if config.metrics_os_enabled {
            cmd.arg("--metrics-os-enabled");
        } else {
            cmd.arg("--no-metrics-os-enabled");
        }

        // Worker
        if config.metrics_workers_enabled {
            cmd.arg("--metrics-workers-enabled");
        } else {
            cmd.arg("--no-metrics-workers-enabled");
        }

        // Percentiles
        if config.metrics_percentiles_enabled {
            cmd.arg("--metrics-percentiles-enabled");
        } else {
            cmd.arg("--no-metrics-percentiles-enabled");
        }

        // Top Errors Limit
        cmd.arg("--metrics-top-errors-limit");
        cmd.arg(config.metrics_top_errors_limit.to_string());

        // Then launch child process
        let child = unsafe {
            cmd.pre_exec(move || {
                let flags = libc::fcntl(listen_fd, libc::F_GETFD);
                libc::fcntl(listen_fd, libc::F_SETFD, flags & !libc::FD_CLOEXEC);
                Ok(())
            })
            .spawn()
            .map_err(|e| FalcornError::runtime(format!("Failed to spawn worker {}: {}", id, e)))
        }?;

        let pid = child.id() as i32;
        worker.pid = Some(pid);
        worker.child = Some(child);
        worker.state = WorkerState::Running;

        self.logger.info(|| {
            format!(
                "[Master {}] Spawned worker {} with PID {}",
                self.master_pid, id, pid
            )
        });

        self.workers.insert(id, worker);
        self.refresh_snapshots();

        Ok(())
    }

    fn refresh_snapshots(&self) {
        let mut snapshots = Vec::with_capacity(self.workers.len());
        for worker in self.workers.values() {
            let state = match worker.state {
                WorkerState::Starting => "starting",
                WorkerState::Running => "running",
                WorkerState::Stopping => "stopping",
                WorkerState::Stopped => "stopped",
                WorkerState::Failed => "failed",
            };
            snapshots.push(WorkerSnapshot {
                id: worker.id,
                pid: worker.pid,
                state: state.to_string(),
                restarts: worker.restarts,
                uptime_secs: worker.start_time.elapsed().as_secs(),
            });
        }

        if let Ok(mut guard) = self.snapshots.lock() {
            guard.workers = snapshots;
        }
    }

    fn process_commands(&mut self) {
        let mut pending = Vec::new();
        if let Ok(mut guard) = self.commands.lock() {
            while let Some(cmd) = guard.pop_front() {
                pending.push(cmd);
            }
        }

        for command in pending {
            match command {
                ControlCommand::ScaleTo {
                    workers,
                    respond_to,
                } => {
                    let result = match self.scale_to(workers) {
                        Ok(message) => CommandResult { ok: true, message },
                        Err(e) => CommandResult {
                            ok: false,
                            message: e.to_string(),
                        },
                    };
                    let _ = respond_to.send(result);
                }
                ControlCommand::RestartWorker {
                    id,
                    graceful,
                    respond_to,
                } => {
                    let result = match self.restart_worker(id, graceful) {
                        Ok(message) => CommandResult { ok: true, message },
                        Err(e) => CommandResult {
                            ok: false,
                            message: e.to_string(),
                        },
                    };
                    let _ = respond_to.send(result);
                }
                ControlCommand::Shutdown {
                    graceful,
                    respond_to,
                } => {
                    let result = match self.shutdown_workers(graceful) {
                        Ok(_) => CommandResult {
                            ok: true,
                            message: "shutdown initiated".to_string(),
                        },
                        Err(e) => CommandResult {
                            ok: false,
                            message: e.to_string(),
                        },
                    };
                    let _ = respond_to.send(result);
                }
                ControlCommand::ReloadConfig {
                    path,
                    rolling,
                    respond_to,
                } => {
                    let result = match self.reload_config(&path, rolling) {
                        Ok(message) => CommandResult { ok: true, message },
                        Err(e) => CommandResult {
                            ok: false,
                            message: e.to_string(),
                        },
                    };
                    let _ = respond_to.send(result);
                }
            }
        }
    }

    fn scale_to(&mut self, target: usize) -> Result<String> {
        let current = self.workers.len();
        if target == current {
            return Ok("worker count unchanged".to_string());
        }
        if target > current {
            let mut spawned = 0;
            while self.workers.len() < target {
                let id = self.next_worker_id();
                self.spawn_worker(id)?;
                spawned += 1;
            }
            return Ok(format!("scaled up by {} workers", spawned));
        }

        let mut ids: Vec<u32> = self.workers.keys().copied().collect();
        ids.sort_unstable_by(|a, b| b.cmp(a));
        let mut stopped = 0;
        let mut remaining = self.workers.len();
        for id in ids {
            if remaining <= target {
                break;
            }
            if self.stop_worker(id, true).is_ok() {
                stopped += 1;
                remaining = remaining.saturating_sub(1);
            }
        }
        Ok(format!("scale down initiated for {} workers", stopped))
    }

    fn restart_worker(&mut self, id: Option<u32>, graceful: bool) -> Result<String> {
        let mut ids: Vec<u32> = match id {
            Some(id) => vec![id],
            None => self.workers.keys().copied().collect(),
        };
        ids.sort_unstable();

        let mut scheduled = 0;
        for worker_id in ids {
            if self.schedule_restart(worker_id, graceful).is_ok() {
                scheduled += 1;
            }
        }
        Ok(format!("restart scheduled for {} workers", scheduled))
    }

    fn schedule_restart(&mut self, id: u32, graceful: bool) -> Result<()> {
        if let Some(worker) = self.workers.get_mut(&id) {
            worker.manual_stop = false;
            worker.pending_restart = true;
            worker.state = WorkerState::Stopping;
            if let Some(pid) = worker.pid {
                let signal = if graceful {
                    Signal::SIGTERM
                } else {
                    Signal::SIGKILL
                };
                signal::kill(Pid::from_raw(pid), signal).map_err(|e| {
                    FalcornError::runtime(format!("Failed to signal worker {}: {}", id, e))
                })?;
            }
            return Ok(());
        }
        Err(FalcornError::runtime(format!("Worker {} not found", id)))
    }

    fn stop_worker(&mut self, id: u32, graceful: bool) -> Result<()> {
        if let Some(worker) = self.workers.get_mut(&id) {
            worker.manual_stop = true;
            worker.pending_restart = false;
            worker.state = WorkerState::Stopping;
            if let Some(pid) = worker.pid {
                let signal = if graceful {
                    Signal::SIGTERM
                } else {
                    Signal::SIGKILL
                };
                signal::kill(Pid::from_raw(pid), signal).map_err(|e| {
                    FalcornError::runtime(format!("Failed to signal worker {}: {}", id, e))
                })?;
            }
            return Ok(());
        }
        Err(FalcornError::runtime(format!("Worker {} not found", id)))
    }

    fn reload_config(&mut self, path: &str, rolling: bool) -> Result<String> {
        let mut config = ServerConfig::from_toml(path)?;
        config.validate()?;
        config.config_path = Some(path.to_string());

        {
            let mut guard = self.config.lock().expect("config mutex poisoned");
            *guard = config;
        }

        if rolling {
            self.start_rolling_restart();
            Ok("config reloaded; rolling restart initiated".to_string())
        } else {
            let _ = self.restart_worker(None, true)?;
            Ok("config reloaded; restart initiated".to_string())
        }
    }

    fn start_rolling_restart(&mut self) {
        let mut ids: Vec<u32> = self.workers.keys().copied().collect();
        ids.sort_unstable();
        self.rolling_restart_queue = ids.into();
    }

    fn process_rolling_restart(&mut self) {
        if self.rolling_restart_queue.is_empty() {
            return;
        }
        if self.has_restart_in_progress() {
            return;
        }
        if let Some(id) = self.rolling_restart_queue.pop_front() {
            let _ = self.schedule_restart(id, true);
        }
    }

    fn has_restart_in_progress(&self) -> bool {
        self.workers
            .values()
            .any(|w| w.pending_restart || w.state == WorkerState::Stopping)
    }

    fn next_worker_id(&self) -> u32 {
        let mut id = 0u32;
        while self.workers.contains_key(&id) {
            id += 1;
        }
        id
    }

    /// Monitor and restart workers if needed
    pub fn monitor_workers(&mut self) -> Result<()> {
        self.logger.info(|| {
            format!(
                "[Master {}] Starting worker monitoring loop",
                self.master_pid
            )
        });

        while !self.shutdown.load(Ordering::Relaxed) {
            self.process_commands();
            self.process_rolling_restart();

            // Check each worker state
            let worker_ids: Vec<u32> = self.workers.keys().copied().collect();

            for id in worker_ids {
                if let Some(worker) = self.workers.get_mut(&id) {
                    if let Some(ref mut child) = worker.child {
                        // Is running ??
                        match child.try_wait() {
                            Ok(Some(status)) => {
                                // Worker exited with status.
                                self.logger.warn(|| {
                                    format!(
                                        "[Master {}] Worker {} (PID {}) exited with status: {}",
                                        self.master_pid,
                                        id,
                                        worker.pid.unwrap_or(-1),
                                        status
                                    )
                                });

                                if worker.pending_restart && !self.shutdown.load(Ordering::Relaxed)
                                {
                                    self.logger.info(|| {
                                        format!(
                                            "[Master {}] Restarting worker {} (manual restart)",
                                            self.master_pid, id
                                        )
                                    });
                                    self.workers.remove(&id);
                                    self.spawn_worker(id)?;
                                    continue;
                                }

                                if worker.manual_stop {
                                    self.workers.remove(&id);
                                    continue;
                                }

                                worker.state = WorkerState::Stopped;
                                worker.restarts += 1;

                                // Restart worker if not shutdown
                                if !self.shutdown.load(Ordering::Relaxed) {
                                    if worker.restarts < 10 {
                                        self.logger.info(|| {
                                            format!(
                                                "[Master {}] Restarting worker {} (restart #{})",
                                                self.master_pid, id, worker.restarts
                                            )
                                        });

                                        // Replace the workerr with a newone
                                        self.workers.remove(&id);
                                        self.spawn_worker(id)?;
                                    } else {
                                        self.logger.error(|| format!(
                                            "[Master {}] Worker {} has crashed too many times, not restarting",
                                            self.master_pid, id
                                        ));
                                        worker.state = WorkerState::Failed;
                                    }
                                }
                            }
                            Ok(None) => {
                                // Worker is running
                                if worker.state != WorkerState::Running {
                                    worker.state = WorkerState::Running;
                                }
                            }
                            Err(e) => {
                                self.logger.error(|| {
                                    format!(
                                        "[Master {}] Error checking worker {} status: {}",
                                        self.master_pid, id, e
                                    )
                                });
                            }
                        }
                    }
                }
            }

            self.refresh_snapshots();

            // Wait 500ms before next iteation
            std::thread::sleep(Duration::from_millis(500));
        }

        // Shutdown all workers gracefully
        self.shutdown_workers(true)?;

        Ok(())
    }

    /// Shuutdown all workers gracefully
    pub fn shutdown_workers(&mut self, graceful: bool) -> Result<()> {
        self.logger.info(|| {
            format!(
                "[Master {}] Shutting down {} workers (graceful: {})",
                self.master_pid,
                self.workers.len(),
                graceful
            )
        });

        self.shutdown.store(true, Ordering::Relaxed);

        let signal = if graceful {
            Signal::SIGTERM
        } else {
            Signal::SIGKILL
        };

        // Send signal to all workers
        for (id, worker) in self.workers.iter_mut() {
            if let Some(pid) = worker.pid {
                self.logger.info(|| {
                    format!(
                        "[Master {}] Sending {:?} to worker {} (PID {})",
                        self.master_pid, signal, id, pid
                    )
                });

                if let Err(e) = signal::kill(Pid::from_raw(pid), signal) {
                    self.logger.error(|| {
                        format!(
                            "[Master {}] Failed to signal worker {} (PID {}): {}",
                            self.master_pid, id, pid, e
                        )
                    });
                }

                worker.state = WorkerState::Stopping;
            }
        }

        // Wait for all workers to be stoped (with timeout)
        if graceful {
            let timeout = Duration::from_secs(5);
            let start = std::time::Instant::now();

            while start.elapsed() < timeout {
                let mut all_stopped = true;

                for worker in self.workers.values_mut() {
                    if let Some(ref mut child) = worker.child {
                        match child.try_wait() {
                            Ok(Some(_)) => {
                                worker.state = WorkerState::Stopped;
                            }
                            Ok(None) => {
                                all_stopped = false;
                            }
                            Err(e) => {
                                self.logger.error(|| {
                                    format!(
                                        "[Master {}] Error waiting for worker {}: {}",
                                        self.master_pid, worker.id, e
                                    )
                                });
                            }
                        }
                    }
                }

                if all_stopped {
                    self.logger.info(|| {
                        format!(
                            "[Master {}] ✓ All workers stopped gracefully",
                            self.master_pid
                        )
                    });
                    return Ok(());
                }

                std::thread::sleep(Duration::from_millis(100));
            }

            // Force kill if is timeout
            self.logger.warn(|| {
                format!(
                    "[Master {}] Graceful shutdown timeout, force killing workers",
                    self.master_pid
                )
            });

            for (id, worker) in self.workers.iter() {
                if worker.state != WorkerState::Stopped {
                    if let Some(pid) = worker.pid {
                        let _ = signal::kill(Pid::from_raw(pid), Signal::SIGKILL);

                        self.logger.warn(|| {
                            format!(
                                "[Master {}] Force killed worker {} (PID {})",
                                self.master_pid, id, pid
                            )
                        });
                    }
                }
            }
        }

        // Cleanup zomies
        for worker in self.workers.values_mut() {
            if let Some(ref mut child) = worker.child {
                let _ = child.wait();
            }
        }

        self.refresh_snapshots();

        Ok(())
    }

    /// Get Workers status
    pub fn get_status(&self) -> String {
        let mut status = format!("[Master {}] Worker Status:\n", self.master_pid);

        for (id, worker) in &self.workers {
            status.push_str(&format!(
                "  Worker {}: PID={:?}, State={:?}, Restarts={}, Uptime={:.2}s\n",
                id,
                worker.pid,
                worker.state,
                worker.restarts,
                worker.start_time.elapsed().as_secs_f64()
            ));
        }

        status
    }

    /// Restart all workers (graceful restart)
    pub fn reload_workers(&mut self) -> Result<()> {
        self.logger
            .info(|| format!("[Master {}] Reloading all workers", self.master_pid));

        // Rolling restart strategy
        let config = self.config.lock().expect("config mutex poisoned").clone();
        for id in 0..config.worker_count() {
            let worker_id = id as u32;

            // spawn a new worker
            let new_id = config.worker_count() as u32 + worker_id;
            self.spawn_worker(new_id)?;

            // wait for worker to be ready
            std::thread::sleep(Duration::from_secs(2));

            // Stop the older
            if let Some(worker) = self.workers.get_mut(&worker_id) {
                if let Some(pid) = worker.pid {
                    let _ = signal::kill(Pid::from_raw(pid), Signal::SIGTERM);
                    worker.state = WorkerState::Stopping;
                }
            }

            // Wait for it to be stoped
            std::thread::sleep(Duration::from_secs(1));

            // cleanup
            self.workers.remove(&worker_id);

            // Store the new worker
            if let Some(new_worker) = self.workers.remove(&new_id) {
                self.workers.insert(worker_id, new_worker);
            }
        }

        self.logger
            .info(|| format!("[Master {}] All workers reloaded", self.master_pid));

        Ok(())
    }
}
