mod config_bootstrap;
mod daemon_runtime;
mod diagnostics;
#[cfg(all(
    feature = "embedded-fips",
    any(target_os = "linux", target_os = "macos")
))]
mod fips_host_tunnel;
#[cfg(feature = "embedded-fips")]
mod fips_private_mesh;
#[cfg(target_os = "linux")]
mod linux_network;
#[cfg(any(target_os = "macos", test))]
mod macos_network;
#[cfg(any(target_os = "macos", test))]
mod macos_service;
mod network_signaling;
#[cfg(all(
    feature = "embedded-fips",
    any(target_os = "linux", target_os = "macos")
))]
mod pipeline_profile;
mod platform_routing;
#[cfg(feature = "embedded-fips")]
mod recent_peers_store;
mod service_management;
mod session_runtime;
mod updater;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
mod wg_upstream_runtime;
#[cfg(target_os = "windows")]
mod windows_network;
#[cfg(any(target_os = "windows", test))]
mod windows_tunnel;
#[cfg(target_os = "linux")]
mod wireguard_exit;

use std::collections::{HashMap, HashSet};
#[cfg(target_os = "windows")]
use std::ffi::OsString;
use std::fs;
use std::fs::OpenOptions;
#[cfg(any(target_os = "macos", test))]
use std::hash::{Hash, Hasher};
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
use std::process::{Command as ProcessCommand, Stdio};
#[cfg(test)]
use std::sync::Mutex;
#[cfg(any(target_os = "windows", test))]
use std::sync::OnceLock;
#[cfg(test)]
use std::sync::atomic::{AtomicU32, Ordering};
use std::thread;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

use anyhow::{Context, Result, anyhow};
use clap::{Args, Parser, Subcommand, ValueEnum};
use nostr_vpn_core::config::{
    AppConfig, SharedNetworkRoster, derive_mesh_tunnel_ip, exit_node_default_routes,
    maybe_autoconfigure_node, normalize_advertised_route, normalize_fips_peer_endpoint_hint,
    normalize_nostr_pubkey, normalize_runtime_network_id, parse_wireguard_exit_config,
};
use nostr_vpn_core::control::PeerAnnouncement;
use nostr_vpn_core::data_plane::MeshPeerStatus;
use nostr_vpn_core::diagnostics::{
    HealthIssue, HealthSeverity, NetworkSummary, PortMappingStatus, ProbeState,
};
use nostr_vpn_core::fips_control::{
    NetworkRoster, PeerCapabilities, PeerEndpointHint, SignedRoster, local_fips_dataplane_features,
};
#[cfg(feature = "embedded-fips")]
use nostr_vpn_core::join_requests::{FIPS_JOIN_REQUEST_RETRY_SECS, MeshJoinRequest};
use nostr_vpn_core::magic_dns::{
    MagicDnsResolverConfig, MagicDnsServer, build_magic_dns_records, install_system_resolver,
    uninstall_system_resolver,
};
#[cfg(target_os = "windows")]
use nostr_vpn_core::platform_paths::{
    legacy_config_path_from_dirs_config_dir, windows_default_config_path_for_state,
    windows_machine_config_path_from_program_data_dir,
    windows_service_config_path_from_sc_qc_output,
};
use nostr_vpn_core::signed_rosters::{
    load_signed_rosters, signed_rosters_file_path, upsert_signed_roster,
};
use serde::{Deserialize, Serialize};
use serde_json::json;
#[cfg(target_os = "windows")]
use windows_service::define_windows_service;
#[cfg(target_os = "windows")]
use windows_service::service::{
    ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, ServiceType,
};
#[cfg(target_os = "windows")]
use windows_service::service_control_handler::{self, ServiceControlHandlerResult};
#[cfg(target_os = "windows")]
use windows_service::service_dispatcher;

#[cfg(test)]
pub(crate) use crate::config_bootstrap::default_cli_install_path;
#[cfg(target_os = "windows")]
pub(crate) use crate::config_bootstrap::windows_service_install_config_path;
pub(crate) use crate::config_bootstrap::{
    apply_config_file, apply_devices_override, apply_participants_override, default_config_path,
    default_tunnel_iface, init_config, install_cli, load_or_default_config, print_version,
    uninstall_cli,
};
pub(crate) use crate::daemon_runtime::*;
use crate::diagnostics::{
    PortMappingRuntime, build_health_issues, capture_network_snapshot, detect_captive_portal,
    run_netcheck_report, write_doctor_bundle,
};
#[cfg(test)]
use crate::network_signaling::NETWORK_INVITE_PREFIX;
use crate::network_signaling::{
    RosterEditAction, active_network_invite_code, apply_network_invite_to_active_network,
    maybe_reload_running_daemon, parse_network_invite, queue_active_network_join_request,
    update_active_network_roster,
};
#[cfg(any(test, not(target_os = "windows")))]
pub(crate) use crate::platform_routing::*;
#[cfg(test)]
pub(crate) use crate::service_management::parse_nonzero_pid;
#[cfg(any(target_os = "windows", test))]
pub(crate) use crate::service_management::windows_should_apply_config_via_service;
#[cfg(test)]
pub(crate) use crate::service_management::{
    linux_service_binary_path, linux_service_executable_path_from_unit_contents,
    linux_service_status_from_show_output, linux_service_unit_content,
};
#[cfg(test)]
pub(crate) use crate::service_management::{
    windows_service_bin_path, windows_service_binary_path_from_sc_qc_output,
    windows_service_disabled_from_qc_output, windows_service_status_from_query_output,
};
#[cfg(any(target_os = "macos", test))]
pub(crate) use crate::service_management::{xml_escape, xml_unescape};
pub(crate) use crate::session_runtime::*;
#[cfg(target_os = "linux")]
pub(crate) use crate::wireguard_exit::*;
const DAEMON_CONTROL_STOP_REQUEST: &str = "stop";
const DAEMON_CONTROL_RELOAD_REQUEST: &str = "reload";
const DAEMON_CONTROL_PAUSE_REQUEST: &str = "pause";
const DAEMON_CONTROL_RESUME_REQUEST: &str = "resume";
const DAEMON_STATUS_MODE_ENV: &str = "NVPN_DAEMON_STATUS_MODE";
const DAEMON_STATUS_MODE_STATE_FILE: &str = "state-file";
const DAEMON_STATE_RUNNING_MAX_AGE_SECS_ENV: &str = "NVPN_DAEMON_STATE_RUNNING_MAX_AGE_SECS";
const DEFAULT_DAEMON_STATE_RUNNING_MAX_AGE_SECS: u64 = 10;
const DAEMON_STATE_RUNNING_MAX_FUTURE_SKEW_SECS: u64 = 2;
const DAEMON_PEER_STATUS_MAX_FUTURE_SKEW_SECS: u64 = 2;
const MAJOR_LINK_CHANGE_TIME_JUMP_SECS: u64 = 30;
const WAITING_FOR_PARTICIPANTS_STATUS: &str = "Waiting for participants";
const LISTENING_FOR_JOIN_REQUESTS_STATUS: &str = "Listening for join requests";
const PRODUCT_VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(target_os = "windows")]
const MAGIC_DNS_PORT: u16 = 53;
#[cfg(not(target_os = "windows"))]
const MAGIC_DNS_PORT: u16 = 1053;
#[cfg(any(target_os = "windows", test))]
const WINDOWS_DAEMON_STATE_FRESHNESS_SECS: u64 = 5;
#[cfg(any(target_os = "macos", test))]
const MACOS_SERVICE_LABEL: &str = "to.nostrvpn.nvpn";
#[cfg(target_os = "linux")]
const LINUX_SERVICE_UNIT_NAME: &str = "nvpn.service";
#[cfg(target_os = "windows")]
const WINDOWS_SERVICE_NAME: &str = "NvpnService";
#[cfg(target_os = "windows")]
const WINDOWS_SERVICE_DISPLAY_NAME: &str = "Nostr VPN";
#[cfg(target_os = "windows")]
const WINDOWS_SERVICE_DESCRIPTION: &str = "Nostr VPN background mesh and tunnel service";
#[cfg(target_os = "windows")]
static WINDOWS_SERVICE_DAEMON_ARGS: OnceLock<DaemonArgs> = OnceLock::new();
#[cfg(target_os = "windows")]
define_windows_service!(ffi_windows_service_main, windows_service_main);

include!("main/cli_args.rs");
include!("main/command_dispatch.rs");
include!("main/wg_self_test.rs");
include!("main/roster_sync.rs");
include!("main/status_types.rs");
include!("main/runtime_helpers.rs");
include!("main/daemon_commands.rs");
include!("main/doctor_and_parsing.rs");
include!("main/lan_pairing.rs");

#[cfg(test)]
pub(crate) use tests::support::{macos_default_routes_from_netstat, macos_ifconfig_has_ipv4};

#[cfg(test)]
mod tests {
    pub(super) use support::control_daemon_request_for_test;

    #[path = "../tests/cli_smoke.rs"]
    mod cli_smoke;
    #[path = "../tests/config_cache.rs"]
    mod config_cache;
    #[path = "../tests/daemon_control.rs"]
    mod daemon_control;
    #[path = "../tests/runtime_misc.rs"]
    mod runtime_misc;
    #[path = "../tests/service_cli.rs"]
    mod service_cli;
    #[path = "../tests/support.rs"]
    pub(crate) mod support;
}
