//! Router types

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

use crate::VpcId;

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

impl RouterId {
    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 RouterId {
    fn default() -> Self {
        Self::new()
    }
}

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

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

impl Default for RouterStatus {
    fn default() -> Self {
        Self::Provisioning
    }
}

/// Tenant-scoped logical router with SNAT configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Router {
    pub id: RouterId,
    pub org_id: String,
    pub project_id: String,
    pub vpc_id: VpcId,
    pub name: String,
    pub description: Option<String>,
    pub gateway_cidr: String,
    pub mac_address: String,
    pub external_ip: String,
    pub ovn_router_id: String,
    pub ovn_router_port_id: String,
    pub status: RouterStatus,
    pub created_at: u64,
    pub updated_at: u64,
}

impl Router {
    pub fn new(
        name: impl Into<String>,
        org_id: impl Into<String>,
        project_id: impl Into<String>,
        vpc_id: VpcId,
        gateway_cidr: impl Into<String>,
        mac_address: impl Into<String>,
        external_ip: impl Into<String>,
    ) -> Self {
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs();

        Self {
            id: RouterId::new(),
            org_id: org_id.into(),
            project_id: project_id.into(),
            vpc_id,
            name: name.into(),
            description: None,
            gateway_cidr: gateway_cidr.into(),
            mac_address: mac_address.into(),
            external_ip: external_ip.into(),
            ovn_router_id: String::new(),
            ovn_router_port_id: String::new(),
            status: RouterStatus::Active,
            created_at: now,
            updated_at: now,
        }
    }
}

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

    #[test]
    fn test_router_creation() {
        let router = Router::new(
            "edge",
            "org-1",
            "proj-1",
            VpcId::new(),
            "10.0.0.1/24",
            "02:00:00:00:00:01",
            "203.0.113.10",
        );

        assert_eq!(router.name, "edge");
        assert_eq!(router.external_ip, "203.0.113.10");
        assert!(router.ovn_router_id.is_empty());
        assert_eq!(router.status, RouterStatus::Active);
    }
}
