//! Subnet types

use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::{DhcpOptions, VpcId};

/// Unique identifier for a Subnet
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SubnetId(Uuid);

impl SubnetId {
    pub fn new() -> Self {
        Self(Uuid::new_v4())
    }

    pub fn from_uuid(uuid: Uuid) -> Self {
        Self(uuid)
    }

    pub fn as_uuid(&self) -> &Uuid {
        &self.0
    }
}

impl Default for SubnetId {
    fn default() -> Self {
        Self::new()
    }
}

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

/// Subnet status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum SubnetStatus {
    #[default]
    Provisioning,
    Active,
    Updating,
    Deleting,
    Error,
}


/// Subnet within a VPC
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Subnet {
    pub id: SubnetId,
    pub vpc_id: VpcId,
    pub name: String,
    pub description: Option<String>,
    pub cidr_block: String,
    pub gateway_ip: Option<String>,
    pub dhcp_enabled: bool,
    pub dns_servers: Vec<String>,
    pub dhcp_options: Option<DhcpOptions>,
    pub status: SubnetStatus,
    pub created_at: u64,
    pub updated_at: u64,
}

impl Subnet {
    pub fn new(name: impl Into<String>, vpc_id: VpcId, cidr_block: impl Into<String>) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();

        Self {
            id: SubnetId::new(),
            vpc_id,
            name: name.into(),
            description: None,
            cidr_block: cidr_block.into(),
            gateway_ip: None,
            dhcp_enabled: true,
            dns_servers: vec!["8.8.8.8".to_string(), "8.8.4.4".to_string()], // Default Google DNS
            dhcp_options: None,
            status: SubnetStatus::Provisioning,
            created_at: now,
            updated_at: now,
        }
    }
}

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

    #[test]
    fn test_subnet_creation() {
        let vpc_id = VpcId::new();
        let subnet = Subnet::new("test-subnet", vpc_id, "10.0.1.0/24");
        assert_eq!(subnet.name, "test-subnet");
        assert_eq!(subnet.cidr_block, "10.0.1.0/24");
        assert!(subnet.dhcp_enabled);
    }
}
