//! Shared Pulse Platform port configuration.
//!
//! Main rship servers use `5155+`.
//! Non-main defaults stay below 5155:
//! - Sync server:      5150
//! - Asset Store REST: 5153
//! - Asset Store WS:   5154
//! - Link file server: 5152
//! - Link local Myko:  5151

/// First port in the default rship main-node range.
pub const DEFAULT_RSHIP_PORT_BASE: u16 = 5155;

/// Default Asset Store REST port (below the main-node range).
pub const DEFAULT_ASSET_STORE_REST_PORT: u16 = 5153;

/// Default Asset Store WebSocket port (below the main-node range).
pub const DEFAULT_ASSET_STORE_WS_PORT: u16 = 5154;

/// Default sync-server port (below the main-node range).
pub const DEFAULT_SYNC_SERVER_PORT: u16 = 5150;

/// Default Link file server port (below the main-node range).
pub const DEFAULT_LINK_FILE_SERVER_PORT: u16 = 5152;

/// Default Link local Myko port (below the main-node range).
pub const DEFAULT_LINK_LOCAL_MYKO_PORT: u16 = 5151;

fn env_var(name: &str) -> Option<String> {
    #[cfg(target_arch = "wasm32")]
    {
        let _ = name;
        None
    }

    #[cfg(not(target_arch = "wasm32"))]
    {
        std::env::var(name).ok()
    }
}

fn env_port(name: &str) -> Option<u16> {
    env_var(name)?.parse::<u16>().ok()
}

fn parse_port_from_addr(value: &str) -> Option<u16> {
    let no_scheme = value
        .split_once("://")
        .map(|(_, rest)| rest)
        .unwrap_or(value);
    let host_port = no_scheme.split('/').next().unwrap_or(no_scheme);
    host_port.rsplit(':').next()?.parse::<u16>().ok()
}

/// Base port for main rship nodes.
pub fn rship_port_base() -> u16 {
    env_port("RSHIP_PORT_BASE").unwrap_or(DEFAULT_RSHIP_PORT_BASE)
}

/// Main rship node port by zero-based index.
pub fn rship_node_port(node_index: u16) -> u16 {
    rship_port_base().saturating_add(node_index)
}

/// Default local rship WebSocket URL with `/myko` path.
pub fn default_rship_ws_myko_url() -> String {
    format!("ws://localhost:{}/myko", rship_node_port(0))
}

/// Default local rship WebSocket URL without path.
pub fn default_rship_ws_url() -> String {
    format!("ws://localhost:{}", rship_node_port(0))
}

/// Asset Store REST port.
///
/// Resolution order:
/// 1. `ASSET_STORE_REST_PORT`
/// 2. Port parsed from `ASSET_STORE_PUBLIC_ADDRESS`
/// 3. Port parsed from `ASSET_STORE_REST_ADDR`
/// 4. `DEFAULT_ASSET_STORE_REST_PORT`
pub fn asset_store_rest_port() -> u16 {
    env_port("ASSET_STORE_REST_PORT")
        .or_else(|| env_var("ASSET_STORE_PUBLIC_ADDRESS").and_then(|v| parse_port_from_addr(&v)))
        .or_else(|| env_var("ASSET_STORE_REST_ADDR").and_then(|v| parse_port_from_addr(&v)))
        .unwrap_or(DEFAULT_ASSET_STORE_REST_PORT)
}

/// Asset Store WebSocket port.
pub fn asset_store_ws_port() -> u16 {
    env_port("ASSET_STORE_WS_PORT").unwrap_or(DEFAULT_ASSET_STORE_WS_PORT)
}

/// Sync server port.
///
/// Resolution order:
/// 1. `SYNC_SERVER_PORT`
/// 2. Port parsed from `SYNC_SERVER_ADDR`
/// 3. Port parsed from `RSHIP_SYNC_SERVER`
/// 4. `DEFAULT_SYNC_SERVER_PORT`
pub fn sync_server_port() -> u16 {
    env_port("SYNC_SERVER_PORT")
        .or_else(|| env_var("SYNC_SERVER_ADDR").and_then(|v| parse_port_from_addr(&v)))
        .or_else(|| env_var("RSHIP_SYNC_SERVER").and_then(|v| parse_port_from_addr(&v)))
        .unwrap_or(DEFAULT_SYNC_SERVER_PORT)
}

/// Default local sync server URL.
pub fn default_sync_server_ws_url() -> String {
    format!("ws://localhost:{}", sync_server_port())
}

/// Default local sync server host:port address.
pub fn default_sync_server_addr() -> String {
    format!("localhost:{}", sync_server_port())
}

/// Link file server port.
pub fn link_file_server_port() -> u16 {
    env_port("LINK_FILE_SERVER_PORT").unwrap_or(DEFAULT_LINK_FILE_SERVER_PORT)
}

/// Link local Myko port.
pub fn link_local_myko_port() -> u16 {
    env_port("LINK_LOCAL_MYKO_PORT").unwrap_or(DEFAULT_LINK_LOCAL_MYKO_PORT)
}
