pub mod alerts;
pub mod audit;
pub mod auth;
pub mod billing;
pub mod health;
pub mod helpers;
pub mod reports;
pub mod schedules;
pub mod servers;
pub mod setup;
pub mod sync;
pub mod webhooks;

use postgres::NoTls;
use r2d2::Pool;
use r2d2_postgres::PostgresConnectionManager;

pub type PgPool = Pool<PostgresConnectionManager<NoTls>>;

pub struct AppState {
    pub pool: PgPool,
    pub admin_username: String,
    pub admin_email: String,
    pub admin_password: String,
}

/// RFC 4648 base32 encode (no padding).
pub fn base32_encode(data: &[u8]) -> String {
    const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    let mut result = String::new();
    let mut buffer: u64 = 0;
    let mut bits_left = 0;
    for &byte in data {
        buffer = (buffer << 8) | byte as u64;
        bits_left += 8;
        while bits_left >= 5 {
            bits_left -= 5;
            result.push(ALPHABET[((buffer >> bits_left) & 0x1F) as usize] as char);
        }
    }
    if bits_left > 0 {
        buffer <<= 5 - bits_left;
        result.push(ALPHABET[(buffer & 0x1F) as usize] as char);
    }
    result
}

/// RFC 4648 base32 decode.
pub fn base32_decode(input: &str) -> Option<Vec<u8>> {
    let input = input.trim_end_matches('=');
    let mut buffer: u64 = 0;
    let mut bits_left = 0;
    let mut result = Vec::new();
    for c in input.chars() {
        let val = match c {
            'A'..='Z' => c as u64 - 'A' as u64,
            '2'..='7' => c as u64 - '2' as u64 + 26,
            'a'..='z' => c as u64 - 'a' as u64,
            _ => return None,
        };
        buffer = (buffer << 5) | val;
        bits_left += 5;
        if bits_left >= 8 {
            bits_left -= 8;
            result.push(((buffer >> bits_left) & 0xFF) as u8);
        }
    }
    Some(result)
}
