use std::{env, process::Stdio};

use crossfire::{MAsyncTx, mpsc};
use futures_util::stream::StreamExt;
use listen_signal::STOP_OR_RELOAD;
use log::{error, info, warn};
use nix::{
  sys::signal::{self, Signal},
  unistd::Pid,
};
use signal_hook::consts::{SIGHUP, SIGINT, SIGTERM};
use signal_hook_tokio::Signals;
use tokio::process::Command;

/// Worker 模式环境变量名 / Worker mode environment variable name
const SYSTEMD_RELOAD_WORKER: &str = "SYSTEMD_RELOAD_WORKER";

/// 子进程退出时的事件结构 / Process exit event structure
pub struct Exit {
  pub pid: u32,
  pub code: Option<i32>,
}

/// 核心管理器
pub struct Run {
  pid_li: Vec<u32>,
}

impl Default for Run {
  fn default() -> Self {
    Self::new()
  }
}

impl Run {
  pub fn new() -> Self {
    Self { pid_li: Vec::new() }
  }

  /// 启动 Run 主循环
  pub async fn run(mut self) {
    // 1. 创建一个通道，用于监听所有子进程的退出事件
    let (tx, rx) = mpsc::bounded_async::<Exit>(32);

    // 2. 首次启动 Worker
    if let Some(pid) = self.spawn(tx.clone()) {
      self.pid_li.push(pid);
    }

    let mut signals = Signals::new(STOP_OR_RELOAD).expect("Failed to register signal handler");

    info!("管理器已启动，PID: {}", std::process::id());

    loop {
      tokio::select! {
          // 信号处理
          Some(signal) = signals.next() => {
              if self.handle_signal(signal, &tx) {
                  break;
              }
          }

          // 子进程退出事件处理 (通过 channel 异步接收)
          Ok(event) = rx.recv() => {
              self.handle_exit_event(event, &tx);
          }
      }
    }
  }

  /// 处理系统信号 / Handle system signals
  fn handle_signal(&mut self, signal: i32, tx: &MAsyncTx<Exit>) -> bool {
    match signal {
      SIGHUP => {
        self.handle_reload_signal(tx);
        false
      }
      SIGTERM | SIGINT => {
        info!("收到退出信号 {signal}，开始关闭...");
        self.shutdown();
        true // 返回true表示需要退出主循环
      }
      _ => {
        warn!("收到未知的信号: {signal}");
        false
      }
    }
  }

  /// 处理重载信号 / Handle reload signal
  fn handle_reload_signal(&mut self, tx: &MAsyncTx<Exit>) {
    info!("收到 SIGHUP 信号，开始滚动更新...");

    // A. 启动新的
    if let Some(new_pid) = self.spawn(tx.clone()) {
      info!("新工作进程已启动: {new_pid}");

      // B. 给旧的发送 SIGINT，让它们自己处理退出
      for old_pid in &self.pid_li {
        info!("向旧工作进程 {old_pid} 发送退出信号...");
        let _ = signal::kill(Pid::from_raw(*old_pid as i32), Signal::SIGINT);
      }

      // C. 更新列表，现在只剩下新的了
      self.pid_li.push(new_pid);
    }
  }

  /// 处理子进程退出事件 / Handle child process exit event
  fn handle_exit_event(&mut self, event: Exit, tx: &MAsyncTx<Exit>) {
    info!(
      "子进程 {pid} 已退出，退出码: {code:?}",
      pid = event.pid,
      code = event.code
    );

    // 确保从活跃列表中移除 (虽然 SIGHUP 逻辑里已经移除了，但防止意外退出的情况)
    self.pid_li.retain(|&x| x != event.pid);

    // 如果所有子进程都死光了，Run 是否要退出？
    // 通常为了保活，我们不退出，或者选择重启一个新的
    if self.pid_li.is_empty() {
      warn!("所有工作进程都已死亡，正在启动新进程");
      if let Some(pid) = self.spawn(tx.clone()) {
        self.pid_li.push(pid);
      }
    }
  }

  /// 核心逻辑：自我复制启动
  fn spawn(&self, tx: MAsyncTx<Exit>) -> Option<u32> {
    let current_exe = env::current_exe().ok()?;

    // 自动获取当前所有参数
    let args: Vec<String> = env::args().skip(1).collect();

    let mut cmd = Command::new(current_exe);
    cmd.args(args);

    // 【关键】设置环境变量，标记这是 Worker，防止无限递归
    cmd.env(SYSTEMD_RELOAD_WORKER, "1");

    // 继承标准输出，方便看日志
    cmd.stdout(Stdio::inherit());
    cmd.stderr(Stdio::inherit());

    // 必须 kill_on_drop(false)，我们要手动管理
    cmd.kill_on_drop(false);

    match cmd.spawn() {
      Ok(mut child) => {
        let pid = child.id().expect("child has no PID");

        // 【关键】启动一个轻量级 Tokio 任务来专门"监视"这个子进程
        // 当它退出时，通过 Channel 通知主循环
        tokio::spawn(async move {
          let status = child.wait().await;
          let code = status.ok().and_then(|s| s.code());
          let _ = tx.send(Exit { pid, code }).await;
        });

        Some(pid)
      }
      Err(e) => {
        error!("启动工作进程失败: {e}");
        None
      }
    }
  }

  fn shutdown(&mut self) {
    info!(
      "正在关闭，终止 {count} 个工作进程...",
      count = self.pid_li.len()
    );

    // 发送SIGTERM信号给所有子进程
    for &pid in &self.pid_li {
      info!("向进程 {pid} 发送SIGTERM信号");
      let _ = signal::kill(Pid::from_raw(pid as i32), Signal::SIGTERM);
    }

    // 等待子进程退出，最多等待30秒
    let start = std::time::Instant::now();
    let timeout = std::time::Duration::from_secs(30);

    // 使用Vec跟踪还活着的进程，避免每次遍历全部 / Use Vec to track alive processes, avoid full iteration each time
    let mut alive_pids: Vec<u32> = self.pid_li.clone();

    while start.elapsed() < timeout && !alive_pids.is_empty() {
      // 检查每个进程是否还存在，发现死掉的就从vec中删除 / Check each process, remove dead ones from vec
      alive_pids.retain(|&pid| {
        let still_alive = signal::kill(Pid::from_raw(pid as i32), None).is_ok();
        if !still_alive {
          info!("进程 {pid} 已正常退出");
        }
        still_alive
      });

      if alive_pids.is_empty() {
        info!("所有工作进程已正常退出");
        return;
      }

      std::thread::sleep(std::time::Duration::from_secs(1));
    }

    // 如果超时，强制杀死剩余进程 / Force kill remaining processes if timeout
    if !alive_pids.is_empty() {
      warn!("等待超时，强制终止剩余进程");
      for &pid in &alive_pids {
        info!("强制终止进程 {pid}");
        let _ = signal::kill(Pid::from_raw(pid as i32), Signal::SIGKILL);
      }
    }

    self.pid_li.clear();
  }
}
