#![cfg_attr(docsrs, feature(doc_cfg))]

use std::net::{Ipv6Addr, SocketAddr, TcpListener};

use socket2::{Domain, Socket, Type};

pub fn listen(port: u16) -> std::io::Result<TcpListener> {
  // =======================================================================
  // 1. Systemd Socket Activation / 热重启逻辑
  // =======================================================================
  // 我们优先检查是否存在 Systemd 传递进来的 FD (通常是 FD 3)。
  // 如果存在，我们必须【复制 (dup)】一份，而不要直接占用原始 FD 3。
  // 这样做的目的是：
  //    FD 3 永远保持 "Open" 状态，不被 Rust 的对象生命周期管理。
  //    当本函数返回的 TcpListener 被 Drop 时，它只会关闭复制出来的 FD，
  //    而不会误杀 FD 3，确保下一次热重启能再次成功获取 FD 3。
  // =======================================================================
  #[cfg(target_os = "linux")]
  {
    use std::os::unix::io::FromRawFd;
    // 简单的检查：FD 3 是否有效 ？
    if unsafe { libc::fcntl(3, libc::F_GETFD) } >= 0 {
      log::info!("listenfd socket detected (FD 3).");

      // 关键步骤：复制 FD 3 -> 生成一个新的 FD (例如 4)
      let new_fd = unsafe { libc::dup(3) };

      if new_fd < 0 {
        // 这种情况极少发生 (系统资源耗尽)，如果发生则回退到手动 bind 或报错
        log::error!(
          "❌ failed to duplicate systemd FD {}",
          std::io::Error::last_os_error()
        );
      } else {
        log::info!("FD 3 duplicated to FD {new_fd}");

        // 将复制出来的 new_fd 交给 TcpListener 管理
        // TcpListener 拥有 new_fd 的所有权，Drop 时会自动关闭 new_fd
        return Ok(unsafe { TcpListener::from_raw_fd(new_fd) });
      }
    }
  }

  // =======================================================================
  // 2. 冷启动 / 本地开发逻辑 (Socket2 手动 Bind)
  // =======================================================================
  // 如果没有继承到 FD，说明是第一次冷启动（非 Systemd 环境）或 Systemd 未配置 Socket。
  // 我们手动创建一个支持双栈 (IPv4 + IPv6) 的 Socket。
  // =======================================================================
  log::info!("🚀 Binding to port {} (Fresh start)", port);

  // 创建 IPv6 Socket (Linux 上 IPv6 socket 默认可以兼容 IPv4)
  let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;

  // 允许端口复用 (SO_REUSEADDR)
  // 这对重启服务非常重要，防止出现 "Address already in use"
  socket.set_reuse_address(true)?;

  // (可选) SO_REUSEPORT
  // 如果你想让多个进程绑定同一个端口，或者提高性能，可以开启。
  // 在 Systemd Socket 模式下由 Systemd 处理，这里是 fallback。
  #[cfg(all(unix, not(target_os = "solaris"), not(target_os = "illumos")))]
  {
    let _ = socket.set_reuse_port(true);
  }

  // 设置为双栈模式 (Dual Stack)
  // false = 既处理 IPv6 也处理 IPv4 (映射为 IPv6)
  socket.set_only_v6(false)?;

  // 设置非阻塞模式 (Tokio 需要)
  socket.set_nonblocking(true)?;

  // 绑定地址 [::]:port (同时覆盖 0.0.0.0:port)
  let addr = SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), port);
  socket.bind(&addr.into())?;

  // 开始监听，backlog 设置为 1024
  socket.listen(1024)?;

  Ok(socket.into())
}
