use super::{HetznerClient, Network, Result};
use crate::config::NetworkConfig;
use serde::{Deserialize, Serialize};
use tracing::info;

pub struct NetworkManager {
    client: HetznerClient,
}

#[derive(Debug, Serialize)]
struct CreateNetworkRequest {
    name: String,
    ip_range: String,
    subnets: Vec<SubnetSpec>,
}

#[derive(Debug, Serialize)]
struct SubnetSpec {
    ip_range: String,
    network_zone: String,
    #[serde(rename = "type")]
    subnet_type: String,
}

#[derive(Debug, Deserialize)]
struct CreateNetworkResponse {
    network: Network,
}

#[derive(Debug, Deserialize)]
struct ListNetworksResponse {
    networks: Vec<Network>,
}

impl NetworkManager {
    pub fn new(client: HetznerClient) -> Self {
        Self { client }
    }

    /// List all networks
    pub async fn list_networks(&self) -> Result<Vec<Network>> {
        let response: ListNetworksResponse = self.client.get("/networks").await?;
        Ok(response.networks)
    }

    /// Get network by name
    pub async fn get_network_by_name(&self, name: &str) -> Result<Option<Network>> {
        let networks = self.list_networks().await?;
        Ok(networks.into_iter().find(|n| n.name == name))
    }

    /// Create a new network
    pub async fn create_network(&self, config: &NetworkConfig) -> Result<Network> {
        info!("Creating network: {}", config.name);

        let request = CreateNetworkRequest {
            name: config.name.clone(),
            ip_range: config.ip_range.clone(),
            subnets: vec![SubnetSpec {
                ip_range: config.ip_range.clone(),
                network_zone: config.zone.clone(),
                subnet_type: "cloud".to_string(),
            }],
        };

        let response: CreateNetworkResponse = self.client.post("/networks", &request).await?;
        info!("Network {} created", config.name);

        Ok(response.network)
    }

    /// Delete a network
    pub async fn delete_network(&self, id: u64) -> Result<()> {
        info!("Deleting network with ID: {}", id);
        self.client.delete(&format!("/networks/{}", id)).await?;
        info!("Network deleted");
        Ok(())
    }

    /// Ensure network exists
    pub async fn ensure_network(&self, config: &NetworkConfig) -> Result<Network> {
        if let Some(network) = self.get_network_by_name(&config.name).await? {
            info!("Network {} already exists", config.name);
            return Ok(network);
        }

        self.create_network(config).await
    }
}
