use crate::repository::api::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Debug, Serialize, Deserialize)]
pub struct AddIPRequest {
    ip: String,
    pool: PoolType,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RemoveIPRequest {
    ip: String,
    pool: PoolType,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct WhitelistResponse {
    message: String,
}

/// Get the list of whitelisted IPs for the current user
pub async fn get_whitelist_ips(user_id: String, pool: PoolType) -> Result<Vec<String>> {
    let url = format!("{host}/rpc/get_whitelist_ips", host=&*BACKEND_API_URL);
    log::trace!("fetching {url}", url = url.red());

    let response = reqwest::Client::new()
        .post(&url)
        .header("Authorization", get_auth_token().await?)
        .header("Content-Type", "application/json")
        .header("X-Tg-Id", user_id)
        .json(&json!({ "pool": pool }))
        .send()
        .await?;

    let status = response.status();
    let response_body = response.text().await?;

    if !status.is_success() {
        return Err(Report::msg(format!(
            "Failed to get whitelist IPs: {}",
            prettify_json_or_text(&response_body)
        )));
    }

    let ips: Vec<String> = serde_json::from_str(&response_body)
        .unwrap_or_else(|_| vec![]);
    
    Ok(ips)
}

/// Add an IP address to the whitelist
pub async fn add_ip_to_whitelist(user_id: String, ip: String, pool: PoolType) -> Result<String> {
    let url = format!("{host}/rpc/add_ip_to_whitelist", host=&*BACKEND_API_URL);
    log::trace!("fetching {url}", url = url.red());

    let request = AddIPRequest { ip, pool };

    let response = reqwest::Client::new()
        .post(&url)
        .header("Authorization", get_auth_token().await?)
        .header("Content-Type", "application/json")
        .header("X-Tg-Id", user_id)
        .json(&request)
        .send()
        .await?;

    let status = response.status();
    let response_body = response.text().await?;

    if !status.is_success() {
        return Err(Report::msg(format!(
            "Failed to add IP to whitelist: {}",
            prettify_json_or_text(&response_body)
        )));
    }

    let response_data: WhitelistResponse = serde_json::from_str(&response_body)
        .map_err(|e| Report::msg(format!("Failed to parse response: {}", e)))?;
    
    Ok(response_data.message)
}

/// Remove an IP address from the whitelist
pub async fn remove_ip_from_whitelist(user_id: String, ip: String, pool: PoolType) -> Result<String> {
    let url = format!("{host}/rpc/remove_ip_from_whitelist", host=&*BACKEND_API_URL);
    log::trace!("fetching {url}", url = url.red());

    let request = RemoveIPRequest { ip, pool };

    let response = reqwest::Client::new()
        .post(&url)
        .header("Authorization", get_auth_token().await?)
        .header("Content-Type", "application/json")
        .header("X-Tg-Id", user_id)
        .json(&request)
        .send()
        .await?;

    let status = response.status();
    let response_body = response.text().await?;

    if !status.is_success() {
        return Err(Report::msg(format!(
            "Failed to remove IP from whitelist: {}",
            prettify_json_or_text(&response_body)
        )));
    }

    let response_data: WhitelistResponse = serde_json::from_str(&response_body)
        .map_err(|e| Report::msg(format!("Failed to parse response: {}", e)))?;
    
    Ok(response_data.message)
}

/// Validate IP address format
pub fn validate_ip_address(ip: &str) -> bool {
    use std::net::Ipv4Addr;
    
    if ip.parse::<Ipv4Addr>().is_ok() {
        return true;
    }
    
    if ip.contains('/') {
        let parts: Vec<&str> = ip.split('/').collect();
        if parts.len() == 2 {
            if let (Ok(_), Ok(prefix)) = (parts[0].parse::<Ipv4Addr>(), parts[1].parse::<u8>()) {
                return prefix <= 32;
            }
        }
    }
    
    false
}
