Skip to content
#[derive(Clone)]
pub struct Server {
    address: (String, u16),
    log_level: String,
    db_path: String,
    reset_db: bool,
    admin_username: String,
    admin_password: String,
}

impl Server {
    pub fn new(
        address: (String, u16),
        log_level: String,
        db_path: String,
        reset_db: bool,
        admin_username: String,
        admin_password: String,
    ) -> Self {
        Server {
            address,
            log_level,
            db_path,
            reset_db,
            admin_username,
            admin_password,
        }
    }

    pub fn address(&self) -> (String, u16) {
        self.address.clone()
    }

    pub fn log_level(&self) -> &str {
        &self.log_level
    }

    pub fn db_path(&self) -> &str {
        &self.db_path
    }

    pub fn maybe_reset_database(&self) {
        if !self.reset_db {
            return;
        }

        log::warn!(
            "RESET_DB is set to true, deleting database file: {}",
            self.db_path
        );

        if std::path::Path::new(&self.db_path).exists() {
            if let Err(e) = std::fs::remove_file(&self.db_path) {
                log::error!("Failed to delete database file: {e}");
            } else {
                log::info!("Database file deleted successfully");
            }
        }
    }

    pub fn admin_username(&self) -> &str {
        &self.admin_username
    }

    pub fn admin_password(&self) -> &str {
        &self.admin_password
    }
}

impl std::fmt::Display for Server {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", ascii(self))
    }
}

pub fn from_env() -> Server {
    let port = std::env::var("PORT")
        .unwrap_or_else(|_| "8080".to_string())
        .parse()
        .unwrap_or(8080);
    let log_level = std::env::var("LOG_LEVEL").unwrap_or_else(|_| "info".to_string());
    let db_path = std::env::var("DB_PATH").unwrap_or_else(|_| "hodis.db".to_string());
    let reset_db = std::env::var("RESET_DB").unwrap_or_default() == "true";
    let admin_username = std::env::var("ADMIN_USERNAME").unwrap_or_else(|_| "admin".to_string());
    let admin_password = std::env::var("ADMIN_PASSWORD").unwrap_or_else(|_| "admin".to_string());

    Server::new(
        ("0.0.0.0".to_string(), port),
        log_level,
        db_path,
        reset_db,
        admin_username,
        admin_password,
    )
}

fn ascii(server: &Server) -> String {
    let (_, port) = server.address();
    let url = format!("http://localhost:{port}");
    let version = env!("CARGO_PKG_VERSION");
    format!(
        "

        ▐▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▌
        ▐  HOIS Preseason Challenge  ▌
        ▐▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▌

        Server running at: {url}
        Version: {version}
        "
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_server_new() {
        let server = Server::new(
            ("127.0.0.1".to_string(), 8080),
            "debug".to_string(),
            "hodis.db".to_string(),
            false,
            "admin".to_string(),
            "pass".to_string(),
        );
        assert_eq!(server.address(), ("127.0.0.1".to_string(), 8080));
        assert_eq!(server.log_level(), "debug");
        assert_eq!(server.db_path(), "hodis.db");
    }

    #[test]
    fn test_server_clone() {
        let server = Server::new(
            ("0.0.0.0".to_string(), 80),
            "info".to_string(),
            "hodis.db".to_string(),
            false,
            "admin".to_string(),
            "pass".to_string(),
        );
        let cloned = server.clone();
        assert_eq!(cloned.db_path(), server.db_path());
        assert_eq!(cloned.log_level(), server.log_level());
    }

    #[test]
    fn test_maybe_reset_database_no_flag() {
        let server = Server::new(
            ("0.0.0.0".to_string(), 80),
            "info".to_string(),
            "/tmp/hodis_test_no_reset.db".to_string(),
            false,
            "admin".to_string(),
            "pass".to_string(),
        );
        server.maybe_reset_database();
    }

    #[test]
    fn test_address_returns_clone() {
        let server = Server::new(
            ("0.0.0.0".to_string(), 3000),
            "info".to_string(),
            "hodis.db".to_string(),
            false,
            "admin".to_string(),
            "pass".to_string(),
        );
        let addr = server.address();
        assert_eq!(addr, ("0.0.0.0".to_string(), 3000));
    }

    #[test]
    fn test_admin_credentials() {
        let server = Server::new(
            ("0.0.0.0".to_string(), 80),
            "info".to_string(),
            "hodis.db".to_string(),
            false,
            "superadmin".to_string(),
            "secret123".to_string(),
        );
        assert_eq!(server.admin_username(), "superadmin");
        assert_eq!(server.admin_password(), "secret123");
    }
}