//! Traefik configuration management for Kubernetes
//!
//! This module provides a Rhai DSL for configuring Traefik IngressRoutes,
//! Middlewares, and other Traefik CRDs on Kubernetes clusters.
//!
//! # Example
//!
//! ```rust,ignore
//! use herolib_kubernetes::{KubernetesManager, HttpRouteBuilder, MiddlewareBuilder};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let km = KubernetesManager::new("production").await?;
//!
//!     // Create an HTTP route
//!     let route = HttpRouteBuilder::new("my-app", "production")
//!         .hostname("app.example.com")
//!         .service("my-service", 8080)
//!         .tls_letsencrypt("letsencrypt")
//!         .build()?;
//!
//!     km.apply_traefik_route(&route).await?;
//!     Ok(())
//! }
//! ```

use super::{KubernetesError, KubernetesManager, KubernetesResult};
use kube::api::{Api, Patch, PatchParams};
use kube::core::DynamicObject;
use kube::discovery::ApiResource;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::collections::HashMap;

// ============================================================================
// Traefik CRD Types
// ============================================================================

/// HTTP route configuration for Traefik IngressRoute
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HttpRoute {
    /// Name of the IngressRoute resource
    pub name: String,
    /// Kubernetes namespace
    pub namespace: String,
    /// Hostname(s) to match
    pub hostnames: Vec<String>,
    /// Path prefix rules
    pub path_prefixes: Vec<String>,
    /// Custom match rules (Traefik rule syntax)
    pub custom_rules: Vec<String>,
    /// Target services with weights
    pub services: Vec<ServiceTarget>,
    /// Applied middlewares (namespace/name format)
    pub middlewares: Vec<String>,
    /// TLS configuration
    pub tls: Option<TlsConfig>,
    /// Entrypoints (default: websecure)
    pub entrypoints: Vec<String>,
    /// Priority (higher = matched first)
    pub priority: Option<i32>,
}

/// TCP route configuration for Traefik IngressRouteTCP
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TcpRoute {
    /// Name of the IngressRouteTCP resource
    pub name: String,
    /// Kubernetes namespace
    pub namespace: String,
    /// Traefik entrypoint name
    pub entrypoint: String,
    /// SNI hostnames for TLS routing
    pub sni_hosts: Vec<String>,
    /// SNI regex pattern
    pub sni_regex: Option<String>,
    /// Target service
    pub service: String,
    /// Target port
    pub port: i32,
    /// Enable TLS passthrough
    pub tls_passthrough: bool,
}

/// UDP route configuration for Traefik IngressRouteUDP
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UdpRoute {
    /// Name of the IngressRouteUDP resource
    pub name: String,
    /// Kubernetes namespace
    pub namespace: String,
    /// Traefik entrypoint name
    pub entrypoint: String,
    /// Target service
    pub service: String,
    /// Target port
    pub port: i32,
}

/// Service target with optional weight for load balancing
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServiceTarget {
    /// Service name
    pub name: String,
    /// Service port
    pub port: i32,
    /// Weight for weighted load balancing (default: 1)
    pub weight: Option<i32>,
    /// Namespace (if different from route namespace)
    pub namespace: Option<String>,
}

/// TLS configuration for routes
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
    /// TLS secret name (for pre-existing certificates)
    pub secret_name: Option<String>,
    /// Cert-manager/ACME resolver name
    pub cert_resolver: Option<String>,
    /// TLS options reference (namespace/name)
    pub options: Option<String>,
    /// Domains for certificate
    pub domains: Vec<String>,
}

/// Traefik Middleware configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Middleware {
    /// Name of the Middleware resource
    pub name: String,
    /// Kubernetes namespace
    pub namespace: String,
    /// Middleware type and configuration
    pub spec: MiddlewareSpec,
}

/// Middleware specification types
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum MiddlewareSpec {
    /// Basic authentication
    BasicAuth {
        secret: String,
        realm: Option<String>,
        remove_header: bool,
    },
    /// Forward authentication to external service
    ForwardAuth {
        address: String,
        trust_forward_header: bool,
        auth_response_headers: Vec<String>,
        auth_request_headers: Vec<String>,
    },
    /// Rate limiting
    RateLimit {
        average: i64,
        burst: i64,
        period: String,
        source_criterion: Option<RateLimitSourceCriterion>,
    },
    /// HTTP headers manipulation
    Headers {
        custom_request_headers: HashMap<String, String>,
        custom_response_headers: HashMap<String, String>,
        access_control_allow_origin: Option<String>,
        access_control_allow_methods: Vec<String>,
        access_control_allow_headers: Vec<String>,
        access_control_max_age: Option<i64>,
        ssl_redirect: bool,
        sts_seconds: Option<i64>,
        sts_include_subdomains: bool,
        frame_deny: bool,
        content_type_nosniff: bool,
        browser_xss_filter: bool,
    },
    /// Strip path prefix
    StripPrefix { prefixes: Vec<String> },
    /// Add path prefix
    AddPrefix { prefix: String },
    /// Redirect scheme (HTTP -> HTTPS)
    RedirectScheme {
        scheme: String,
        permanent: bool,
        port: Option<String>,
    },
    /// Redirect regex
    RedirectRegex {
        regex: String,
        replacement: String,
        permanent: bool,
    },
    /// IP whitelist
    IpWhiteList {
        source_range: Vec<String>,
        ip_strategy: Option<IpStrategy>,
    },
    /// Circuit breaker
    CircuitBreaker {
        expression: String,
        check_period: Option<String>,
        fallback_duration: Option<String>,
        recovery_duration: Option<String>,
    },
    /// Retry failed requests
    Retry {
        attempts: i32,
        initial_interval: Option<String>,
    },
    /// Compress responses
    Compress {
        excluded_content_types: Vec<String>,
        min_response_body_bytes: Option<i64>,
    },
    /// Chain multiple middlewares
    Chain { middlewares: Vec<String> },
    /// Replace path
    ReplacePath { path: String },
    /// Replace path regex
    ReplacePathRegex { regex: String, replacement: String },
    /// Buffering
    Buffering {
        max_request_body_bytes: Option<i64>,
        mem_request_body_bytes: Option<i64>,
        max_response_body_bytes: Option<i64>,
        mem_response_body_bytes: Option<i64>,
        retry_expression: Option<String>,
    },
    /// In-flight request limiting
    InFlightReq {
        amount: i64,
        source_criterion: Option<RateLimitSourceCriterion>,
    },
    /// Error pages
    Errors {
        status: Vec<String>,
        service: String,
        query: String,
    },
}

/// Rate limit source criterion configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimitSourceCriterion {
    pub ip_strategy: Option<IpStrategy>,
    pub request_header_name: Option<String>,
    pub request_host: bool,
}

/// IP strategy for extracting client IP
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IpStrategy {
    pub depth: Option<i32>,
    pub excluded_ips: Vec<String>,
}

/// TLS options configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsOption {
    /// Name of the TLSOption resource
    pub name: String,
    /// Kubernetes namespace
    pub namespace: String,
    /// Minimum TLS version
    pub min_version: Option<String>,
    /// Maximum TLS version
    pub max_version: Option<String>,
    /// Allowed cipher suites
    pub cipher_suites: Vec<String>,
    /// Curve preferences
    pub curve_preferences: Vec<String>,
    /// Client authentication configuration
    pub client_auth: Option<ClientAuth>,
    /// SNI strict mode
    pub sni_strict: bool,
    /// ALPN protocols
    pub alpn_protocols: Vec<String>,
}

/// Client authentication configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClientAuth {
    /// CA secret names
    pub ca_secrets: Vec<String>,
    /// Client auth type: NoClientCert, RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, RequireAndVerifyClientCert
    pub client_auth_type: String,
}

// ============================================================================
// Builder Patterns
// ============================================================================

/// Builder for HTTP routes (IngressRoute)
#[derive(Debug, Clone)]
pub struct HttpRouteBuilder {
    route: HttpRoute,
}

impl HttpRouteBuilder {
    /// Create a new HTTP route builder
    pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
        Self {
            route: HttpRoute {
                name: name.into(),
                namespace: namespace.into(),
                hostnames: Vec::new(),
                path_prefixes: Vec::new(),
                custom_rules: Vec::new(),
                services: Vec::new(),
                middlewares: Vec::new(),
                tls: None,
                entrypoints: vec!["websecure".to_string()],
                priority: None,
            },
        }
    }

    /// Add a hostname to match
    pub fn hostname(mut self, hostname: impl Into<String>) -> Self {
        self.route.hostnames.push(hostname.into());
        self
    }

    /// Add multiple hostnames
    pub fn hostnames(mut self, hostnames: Vec<String>) -> Self {
        self.route.hostnames.extend(hostnames);
        self
    }

    /// Add a path prefix rule
    pub fn path_prefix(mut self, prefix: impl Into<String>) -> Self {
        self.route.path_prefixes.push(prefix.into());
        self
    }

    /// Add a custom Traefik rule
    pub fn custom_rule(mut self, rule: impl Into<String>) -> Self {
        self.route.custom_rules.push(rule.into());
        self
    }

    /// Add a target service
    pub fn service(mut self, name: impl Into<String>, port: i32) -> Self {
        self.route.services.push(ServiceTarget {
            name: name.into(),
            port,
            weight: None,
            namespace: None,
        });
        self
    }

    /// Add a weighted service for canary/blue-green deployments
    pub fn weighted_service(
        mut self,
        name: impl Into<String>,
        port: i32,
        weight: i32,
    ) -> Self {
        self.route.services.push(ServiceTarget {
            name: name.into(),
            port,
            weight: Some(weight),
            namespace: None,
        });
        self
    }

    /// Add a service from a different namespace
    pub fn service_external(
        mut self,
        name: impl Into<String>,
        namespace: impl Into<String>,
        port: i32,
    ) -> Self {
        self.route.services.push(ServiceTarget {
            name: name.into(),
            port,
            weight: None,
            namespace: Some(namespace.into()),
        });
        self
    }

    /// Add a middleware reference
    pub fn middleware(mut self, name: impl Into<String>) -> Self {
        self.route.middlewares.push(name.into());
        self
    }

    /// Add a middleware from a specific namespace
    pub fn middleware_ns(mut self, namespace: impl Into<String>, name: impl Into<String>) -> Self {
        self.route
            .middlewares
            .push(format!("{}-{}", namespace.into(), name.into()));
        self
    }

    /// Add multiple middlewares
    pub fn middlewares(mut self, middlewares: Vec<String>) -> Self {
        self.route.middlewares.extend(middlewares);
        self
    }

    /// Configure TLS with a secret
    pub fn tls_secret(mut self, secret_name: impl Into<String>) -> Self {
        let tls = self.route.tls.get_or_insert(TlsConfig {
            secret_name: None,
            cert_resolver: None,
            options: None,
            domains: Vec::new(),
        });
        tls.secret_name = Some(secret_name.into());
        self
    }

    /// Configure TLS with Let's Encrypt / ACME resolver
    pub fn tls_letsencrypt(mut self, resolver_name: impl Into<String>) -> Self {
        let tls = self.route.tls.get_or_insert(TlsConfig {
            secret_name: None,
            cert_resolver: None,
            options: None,
            domains: Vec::new(),
        });
        tls.cert_resolver = Some(resolver_name.into());
        self
    }

    /// Configure TLS options reference
    pub fn tls_options(mut self, options_ref: impl Into<String>) -> Self {
        let tls = self.route.tls.get_or_insert(TlsConfig {
            secret_name: None,
            cert_resolver: None,
            options: None,
            domains: Vec::new(),
        });
        tls.options = Some(options_ref.into());
        self
    }

    /// Add TLS domain
    pub fn tls_domain(mut self, domain: impl Into<String>) -> Self {
        let tls = self.route.tls.get_or_insert(TlsConfig {
            secret_name: None,
            cert_resolver: None,
            options: None,
            domains: Vec::new(),
        });
        tls.domains.push(domain.into());
        self
    }

    /// Enable TLS (minimal config)
    pub fn tls(mut self) -> Self {
        self.route.tls = Some(TlsConfig {
            secret_name: None,
            cert_resolver: None,
            options: None,
            domains: Vec::new(),
        });
        self
    }

    /// Set entrypoints
    pub fn entrypoints(mut self, entrypoints: Vec<String>) -> Self {
        self.route.entrypoints = entrypoints;
        self
    }

    /// Add an entrypoint
    pub fn entrypoint(mut self, entrypoint: impl Into<String>) -> Self {
        self.route.entrypoints.push(entrypoint.into());
        self
    }

    /// Set route priority
    pub fn priority(mut self, priority: i32) -> Self {
        self.route.priority = Some(priority);
        self
    }

    /// Build the HTTP route
    pub fn build(self) -> Result<HttpRoute, &'static str> {
        if self.route.services.is_empty() {
            return Err("At least one service target is required");
        }
        if self.route.hostnames.is_empty()
            && self.route.path_prefixes.is_empty()
            && self.route.custom_rules.is_empty()
        {
            return Err("At least one hostname, path prefix, or custom rule is required");
        }
        Ok(self.route)
    }
}

impl Default for HttpRouteBuilder {
    fn default() -> Self {
        Self::new("", "default")
    }
}

/// Builder for TCP routes (IngressRouteTCP)
#[derive(Debug, Clone)]
pub struct TcpRouteBuilder {
    route: TcpRoute,
}

impl TcpRouteBuilder {
    /// Create a new TCP route builder
    pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
        Self {
            route: TcpRoute {
                name: name.into(),
                namespace: namespace.into(),
                entrypoint: "tcp".to_string(),
                sni_hosts: Vec::new(),
                sni_regex: None,
                service: String::new(),
                port: 0,
                tls_passthrough: false,
            },
        }
    }

    /// Set the Traefik entrypoint
    pub fn entrypoint(mut self, entrypoint: impl Into<String>) -> Self {
        self.route.entrypoint = entrypoint.into();
        self
    }

    /// Add an SNI hostname
    pub fn sni(mut self, hostname: impl Into<String>) -> Self {
        self.route.sni_hosts.push(hostname.into());
        self
    }

    /// Add multiple SNI hostnames
    pub fn sni_hosts(mut self, hosts: Vec<String>) -> Self {
        self.route.sni_hosts.extend(hosts);
        self
    }

    /// Set SNI regex pattern
    pub fn sni_regex(mut self, regex: impl Into<String>) -> Self {
        self.route.sni_regex = Some(regex.into());
        self
    }

    /// Set target service
    pub fn service(mut self, name: impl Into<String>, port: i32) -> Self {
        self.route.service = name.into();
        self.route.port = port;
        self
    }

    /// Enable TLS passthrough
    pub fn tls_passthrough(mut self, enabled: bool) -> Self {
        self.route.tls_passthrough = enabled;
        self
    }

    /// Build the TCP route
    pub fn build(self) -> Result<TcpRoute, &'static str> {
        if self.route.service.is_empty() {
            return Err("Service name is required");
        }
        if self.route.port == 0 {
            return Err("Service port is required");
        }
        Ok(self.route)
    }
}

/// Builder for UDP routes (IngressRouteUDP)
#[derive(Debug, Clone)]
pub struct UdpRouteBuilder {
    route: UdpRoute,
}

impl UdpRouteBuilder {
    /// Create a new UDP route builder
    pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
        Self {
            route: UdpRoute {
                name: name.into(),
                namespace: namespace.into(),
                entrypoint: "udp".to_string(),
                service: String::new(),
                port: 0,
            },
        }
    }

    /// Set the Traefik entrypoint
    pub fn entrypoint(mut self, entrypoint: impl Into<String>) -> Self {
        self.route.entrypoint = entrypoint.into();
        self
    }

    /// Set target service
    pub fn service(mut self, name: impl Into<String>, port: i32) -> Self {
        self.route.service = name.into();
        self.route.port = port;
        self
    }

    /// Build the UDP route
    pub fn build(self) -> Result<UdpRoute, &'static str> {
        if self.route.service.is_empty() {
            return Err("Service name is required");
        }
        if self.route.port == 0 {
            return Err("Service port is required");
        }
        Ok(self.route)
    }
}

/// Builder for Traefik Middlewares
#[derive(Debug, Clone)]
pub struct MiddlewareBuilder {
    name: String,
    namespace: String,
}

impl MiddlewareBuilder {
    /// Create a new middleware builder
    pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            namespace: namespace.into(),
        }
    }

    /// Create a basic auth middleware
    pub fn basic_auth(self, secret: impl Into<String>) -> BasicAuthMiddlewareBuilder {
        BasicAuthMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            secret: secret.into(),
            realm: None,
            remove_header: false,
        }
    }

    /// Create a forward auth middleware
    pub fn forward_auth(self, address: impl Into<String>) -> ForwardAuthMiddlewareBuilder {
        ForwardAuthMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            address: address.into(),
            trust_forward_header: false,
            auth_response_headers: Vec::new(),
            auth_request_headers: Vec::new(),
        }
    }

    /// Create a rate limit middleware
    pub fn rate_limit(self, average: i64, burst: i64) -> RateLimitMiddlewareBuilder {
        RateLimitMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            average,
            burst,
            period: "1s".to_string(),
            source_criterion: None,
        }
    }

    /// Create a headers middleware
    pub fn headers(self) -> HeadersMiddlewareBuilder {
        HeadersMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            custom_request_headers: HashMap::new(),
            custom_response_headers: HashMap::new(),
            access_control_allow_origin: None,
            access_control_allow_methods: Vec::new(),
            access_control_allow_headers: Vec::new(),
            access_control_max_age: None,
            ssl_redirect: false,
            sts_seconds: None,
            sts_include_subdomains: false,
            frame_deny: false,
            content_type_nosniff: false,
            browser_xss_filter: false,
        }
    }

    /// Create a strip prefix middleware
    pub fn strip_prefix(self, prefixes: Vec<String>) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::StripPrefix { prefixes },
        }
    }

    /// Create an add prefix middleware
    pub fn add_prefix(self, prefix: impl Into<String>) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::AddPrefix {
                prefix: prefix.into(),
            },
        }
    }

    /// Create a redirect scheme middleware (e.g., HTTP -> HTTPS)
    pub fn redirect_scheme(
        self,
        scheme: impl Into<String>,
        permanent: bool,
    ) -> RedirectSchemeMiddlewareBuilder {
        RedirectSchemeMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            scheme: scheme.into(),
            permanent,
            port: None,
        }
    }

    /// Create an IP whitelist middleware
    pub fn ip_whitelist(self, source_range: Vec<String>) -> IpWhitelistMiddlewareBuilder {
        IpWhitelistMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            source_range,
            ip_strategy: None,
        }
    }

    /// Create a circuit breaker middleware
    pub fn circuit_breaker(
        self,
        expression: impl Into<String>,
    ) -> CircuitBreakerMiddlewareBuilder {
        CircuitBreakerMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            expression: expression.into(),
            check_period: None,
            fallback_duration: None,
            recovery_duration: None,
        }
    }

    /// Create a retry middleware
    pub fn retry(self, attempts: i32) -> RetryMiddlewareBuilder {
        RetryMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            attempts,
            initial_interval: None,
        }
    }

    /// Create a compress middleware
    pub fn compress(self) -> CompressMiddlewareBuilder {
        CompressMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            excluded_content_types: Vec::new(),
            min_response_body_bytes: None,
        }
    }

    /// Create a chain middleware
    pub fn chain(self, middlewares: Vec<String>) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::Chain { middlewares },
        }
    }

    /// Create a replace path middleware
    pub fn replace_path(self, path: impl Into<String>) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::ReplacePath { path: path.into() },
        }
    }

    /// Create an in-flight request limiting middleware
    pub fn in_flight_req(self, amount: i64) -> InFlightReqMiddlewareBuilder {
        InFlightReqMiddlewareBuilder {
            name: self.name,
            namespace: self.namespace,
            amount,
            source_criterion: None,
        }
    }
}

// Sub-builders for complex middlewares

#[derive(Debug, Clone)]
pub struct BasicAuthMiddlewareBuilder {
    name: String,
    namespace: String,
    secret: String,
    realm: Option<String>,
    remove_header: bool,
}

impl BasicAuthMiddlewareBuilder {
    pub fn realm(mut self, realm: impl Into<String>) -> Self {
        self.realm = Some(realm.into());
        self
    }

    pub fn remove_header(mut self, remove: bool) -> Self {
        self.remove_header = remove;
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::BasicAuth {
                secret: self.secret,
                realm: self.realm,
                remove_header: self.remove_header,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct ForwardAuthMiddlewareBuilder {
    name: String,
    namespace: String,
    address: String,
    trust_forward_header: bool,
    auth_response_headers: Vec<String>,
    auth_request_headers: Vec<String>,
}

impl ForwardAuthMiddlewareBuilder {
    pub fn trust_forward_header(mut self, trust: bool) -> Self {
        self.trust_forward_header = trust;
        self
    }

    pub fn auth_response_header(mut self, header: impl Into<String>) -> Self {
        self.auth_response_headers.push(header.into());
        self
    }

    pub fn auth_response_headers(mut self, headers: Vec<String>) -> Self {
        self.auth_response_headers.extend(headers);
        self
    }

    pub fn auth_request_header(mut self, header: impl Into<String>) -> Self {
        self.auth_request_headers.push(header.into());
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::ForwardAuth {
                address: self.address,
                trust_forward_header: self.trust_forward_header,
                auth_response_headers: self.auth_response_headers,
                auth_request_headers: self.auth_request_headers,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct RateLimitMiddlewareBuilder {
    name: String,
    namespace: String,
    average: i64,
    burst: i64,
    period: String,
    source_criterion: Option<RateLimitSourceCriterion>,
}

impl RateLimitMiddlewareBuilder {
    pub fn period(mut self, period: impl Into<String>) -> Self {
        self.period = period.into();
        self
    }

    pub fn source_by_header(mut self, header_name: impl Into<String>) -> Self {
        self.source_criterion = Some(RateLimitSourceCriterion {
            ip_strategy: None,
            request_header_name: Some(header_name.into()),
            request_host: false,
        });
        self
    }

    pub fn source_by_host(mut self) -> Self {
        self.source_criterion = Some(RateLimitSourceCriterion {
            ip_strategy: None,
            request_header_name: None,
            request_host: true,
        });
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::RateLimit {
                average: self.average,
                burst: self.burst,
                period: self.period,
                source_criterion: self.source_criterion,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct HeadersMiddlewareBuilder {
    name: String,
    namespace: String,
    custom_request_headers: HashMap<String, String>,
    custom_response_headers: HashMap<String, String>,
    access_control_allow_origin: Option<String>,
    access_control_allow_methods: Vec<String>,
    access_control_allow_headers: Vec<String>,
    access_control_max_age: Option<i64>,
    ssl_redirect: bool,
    sts_seconds: Option<i64>,
    sts_include_subdomains: bool,
    frame_deny: bool,
    content_type_nosniff: bool,
    browser_xss_filter: bool,
}

impl HeadersMiddlewareBuilder {
    pub fn add_request_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.custom_request_headers
            .insert(key.into(), value.into());
        self
    }

    pub fn add_response_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.custom_response_headers
            .insert(key.into(), value.into());
        self
    }

    pub fn remove_request_header(mut self, key: impl Into<String>) -> Self {
        self.custom_request_headers.insert(key.into(), String::new());
        self
    }

    pub fn cors_allow_origin(mut self, origin: impl Into<String>) -> Self {
        self.access_control_allow_origin = Some(origin.into());
        self
    }

    pub fn cors_allow_methods(mut self, methods: Vec<String>) -> Self {
        self.access_control_allow_methods = methods;
        self
    }

    pub fn cors_allow_headers(mut self, headers: Vec<String>) -> Self {
        self.access_control_allow_headers = headers;
        self
    }

    pub fn cors_max_age(mut self, seconds: i64) -> Self {
        self.access_control_max_age = Some(seconds);
        self
    }

    pub fn ssl_redirect(mut self, redirect: bool) -> Self {
        self.ssl_redirect = redirect;
        self
    }

    pub fn sts(mut self, seconds: i64, include_subdomains: bool) -> Self {
        self.sts_seconds = Some(seconds);
        self.sts_include_subdomains = include_subdomains;
        self
    }

    pub fn frame_deny(mut self, deny: bool) -> Self {
        self.frame_deny = deny;
        self
    }

    pub fn content_type_nosniff(mut self, enable: bool) -> Self {
        self.content_type_nosniff = enable;
        self
    }

    pub fn browser_xss_filter(mut self, enable: bool) -> Self {
        self.browser_xss_filter = enable;
        self
    }

    /// Apply common security headers
    pub fn security_defaults(self) -> Self {
        self.frame_deny(true)
            .content_type_nosniff(true)
            .browser_xss_filter(true)
            .sts(31536000, true)
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::Headers {
                custom_request_headers: self.custom_request_headers,
                custom_response_headers: self.custom_response_headers,
                access_control_allow_origin: self.access_control_allow_origin,
                access_control_allow_methods: self.access_control_allow_methods,
                access_control_allow_headers: self.access_control_allow_headers,
                access_control_max_age: self.access_control_max_age,
                ssl_redirect: self.ssl_redirect,
                sts_seconds: self.sts_seconds,
                sts_include_subdomains: self.sts_include_subdomains,
                frame_deny: self.frame_deny,
                content_type_nosniff: self.content_type_nosniff,
                browser_xss_filter: self.browser_xss_filter,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct RedirectSchemeMiddlewareBuilder {
    name: String,
    namespace: String,
    scheme: String,
    permanent: bool,
    port: Option<String>,
}

impl RedirectSchemeMiddlewareBuilder {
    pub fn port(mut self, port: impl Into<String>) -> Self {
        self.port = Some(port.into());
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::RedirectScheme {
                scheme: self.scheme,
                permanent: self.permanent,
                port: self.port,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct IpWhitelistMiddlewareBuilder {
    name: String,
    namespace: String,
    source_range: Vec<String>,
    ip_strategy: Option<IpStrategy>,
}

impl IpWhitelistMiddlewareBuilder {
    pub fn ip_strategy_depth(mut self, depth: i32) -> Self {
        let strategy = self.ip_strategy.get_or_insert(IpStrategy {
            depth: None,
            excluded_ips: Vec::new(),
        });
        strategy.depth = Some(depth);
        self
    }

    pub fn ip_strategy_excluded(mut self, excluded: Vec<String>) -> Self {
        let strategy = self.ip_strategy.get_or_insert(IpStrategy {
            depth: None,
            excluded_ips: Vec::new(),
        });
        strategy.excluded_ips = excluded;
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::IpWhiteList {
                source_range: self.source_range,
                ip_strategy: self.ip_strategy,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct CircuitBreakerMiddlewareBuilder {
    name: String,
    namespace: String,
    expression: String,
    check_period: Option<String>,
    fallback_duration: Option<String>,
    recovery_duration: Option<String>,
}

impl CircuitBreakerMiddlewareBuilder {
    pub fn check_period(mut self, period: impl Into<String>) -> Self {
        self.check_period = Some(period.into());
        self
    }

    pub fn fallback_duration(mut self, duration: impl Into<String>) -> Self {
        self.fallback_duration = Some(duration.into());
        self
    }

    pub fn recovery_duration(mut self, duration: impl Into<String>) -> Self {
        self.recovery_duration = Some(duration.into());
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::CircuitBreaker {
                expression: self.expression,
                check_period: self.check_period,
                fallback_duration: self.fallback_duration,
                recovery_duration: self.recovery_duration,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct RetryMiddlewareBuilder {
    name: String,
    namespace: String,
    attempts: i32,
    initial_interval: Option<String>,
}

impl RetryMiddlewareBuilder {
    pub fn initial_interval(mut self, interval: impl Into<String>) -> Self {
        self.initial_interval = Some(interval.into());
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::Retry {
                attempts: self.attempts,
                initial_interval: self.initial_interval,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct CompressMiddlewareBuilder {
    name: String,
    namespace: String,
    excluded_content_types: Vec<String>,
    min_response_body_bytes: Option<i64>,
}

impl CompressMiddlewareBuilder {
    pub fn exclude_content_type(mut self, content_type: impl Into<String>) -> Self {
        self.excluded_content_types.push(content_type.into());
        self
    }

    pub fn excluded_content_types(mut self, types: Vec<String>) -> Self {
        self.excluded_content_types = types;
        self
    }

    pub fn min_response_body_bytes(mut self, bytes: i64) -> Self {
        self.min_response_body_bytes = Some(bytes);
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::Compress {
                excluded_content_types: self.excluded_content_types,
                min_response_body_bytes: self.min_response_body_bytes,
            },
        }
    }
}

#[derive(Debug, Clone)]
pub struct InFlightReqMiddlewareBuilder {
    name: String,
    namespace: String,
    amount: i64,
    source_criterion: Option<RateLimitSourceCriterion>,
}

impl InFlightReqMiddlewareBuilder {
    pub fn source_by_header(mut self, header_name: impl Into<String>) -> Self {
        self.source_criterion = Some(RateLimitSourceCriterion {
            ip_strategy: None,
            request_header_name: Some(header_name.into()),
            request_host: false,
        });
        self
    }

    pub fn build(self) -> Middleware {
        Middleware {
            name: self.name,
            namespace: self.namespace,
            spec: MiddlewareSpec::InFlightReq {
                amount: self.amount,
                source_criterion: self.source_criterion,
            },
        }
    }
}

/// Builder for TLS options
#[derive(Debug, Clone)]
pub struct TlsOptionBuilder {
    option: TlsOption,
}

impl TlsOptionBuilder {
    /// Create a new TLS option builder
    pub fn new(name: impl Into<String>, namespace: impl Into<String>) -> Self {
        Self {
            option: TlsOption {
                name: name.into(),
                namespace: namespace.into(),
                min_version: None,
                max_version: None,
                cipher_suites: Vec::new(),
                curve_preferences: Vec::new(),
                client_auth: None,
                sni_strict: false,
                alpn_protocols: Vec::new(),
            },
        }
    }

    /// Set minimum TLS version
    pub fn min_version(mut self, version: impl Into<String>) -> Self {
        self.option.min_version = Some(version.into());
        self
    }

    /// Set maximum TLS version
    pub fn max_version(mut self, version: impl Into<String>) -> Self {
        self.option.max_version = Some(version.into());
        self
    }

    /// Add cipher suites
    pub fn cipher_suites(mut self, suites: Vec<String>) -> Self {
        self.option.cipher_suites = suites;
        self
    }

    /// Add curve preferences
    pub fn curve_preferences(mut self, curves: Vec<String>) -> Self {
        self.option.curve_preferences = curves;
        self
    }

    /// Configure client authentication
    pub fn client_auth(
        mut self,
        auth_type: impl Into<String>,
        ca_secrets: Vec<String>,
    ) -> Self {
        self.option.client_auth = Some(ClientAuth {
            ca_secrets,
            client_auth_type: auth_type.into(),
        });
        self
    }

    /// Enable SNI strict mode
    pub fn sni_strict(mut self, strict: bool) -> Self {
        self.option.sni_strict = strict;
        self
    }

    /// Set ALPN protocols
    pub fn alpn_protocols(mut self, protocols: Vec<String>) -> Self {
        self.option.alpn_protocols = protocols;
        self
    }

    /// Build the TLS option
    pub fn build(self) -> TlsOption {
        self.option
    }
}

// ============================================================================
// YAML/JSON Generation
// ============================================================================

impl HttpRoute {
    /// Generate Traefik IngressRoute CRD YAML
    pub fn to_yaml(&self) -> String {
        let json = self.to_json();
        serde_yaml::to_string(&json).unwrap_or_default()
    }

    /// Generate Traefik IngressRoute CRD JSON
    pub fn to_json(&self) -> serde_json::Value {
        // Build the match rule
        let mut rules = Vec::new();

        for hostname in &self.hostnames {
            rules.push(format!("Host(`{}`)", hostname));
        }

        for prefix in &self.path_prefixes {
            rules.push(format!("PathPrefix(`{}`)", prefix));
        }

        rules.extend(self.custom_rules.clone());

        let match_rule = if rules.len() == 1 {
            rules[0].clone()
        } else if !rules.is_empty() {
            // Combine hostname rules with path rules using &&
            let hostname_rules: Vec<_> = self
                .hostnames
                .iter()
                .map(|h| format!("Host(`{}`)", h))
                .collect();
            let other_rules: Vec<_> = self
                .path_prefixes
                .iter()
                .map(|p| format!("PathPrefix(`{}`)", p))
                .chain(self.custom_rules.iter().cloned())
                .collect();

            if hostname_rules.is_empty() {
                other_rules.join(" || ")
            } else if other_rules.is_empty() {
                hostname_rules.join(" || ")
            } else {
                format!(
                    "({}) && ({})",
                    hostname_rules.join(" || "),
                    other_rules.join(" || ")
                )
            }
        } else {
            String::new()
        };

        // Build services
        let services: Vec<serde_json::Value> = self
            .services
            .iter()
            .map(|s| {
                let mut svc = json!({
                    "name": s.name,
                    "port": s.port
                });
                if let Some(weight) = s.weight {
                    svc["weight"] = json!(weight);
                }
                if let Some(ns) = &s.namespace {
                    svc["namespace"] = json!(ns);
                }
                svc
            })
            .collect();

        // Build middlewares
        let middlewares: Vec<serde_json::Value> = self
            .middlewares
            .iter()
            .map(|m| {
                if m.contains('-') {
                    // Assume namespace-name format
                    json!({ "name": m })
                } else {
                    json!({ "name": m })
                }
            })
            .collect();

        let mut route_spec = json!({
            "match": match_rule,
            "kind": "Rule",
            "services": services
        });

        if !middlewares.is_empty() {
            route_spec["middlewares"] = json!(middlewares);
        }

        if let Some(priority) = self.priority {
            route_spec["priority"] = json!(priority);
        }

        let mut spec = json!({
            "entryPoints": self.entrypoints,
            "routes": [route_spec]
        });

        if let Some(tls) = &self.tls {
            let mut tls_config = json!({});
            if let Some(secret) = &tls.secret_name {
                tls_config["secretName"] = json!(secret);
            }
            if let Some(resolver) = &tls.cert_resolver {
                tls_config["certResolver"] = json!(resolver);
            }
            if let Some(options) = &tls.options {
                tls_config["options"] = json!({ "name": options });
            }
            if !tls.domains.is_empty() {
                tls_config["domains"] = json!(tls.domains.iter().map(|d| {
                    json!({ "main": d })
                }).collect::<Vec<_>>());
            }
            spec["tls"] = tls_config;
        }

        json!({
            "apiVersion": "traefik.io/v1alpha1",
            "kind": "IngressRoute",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "spec": spec
        })
    }
}

impl TcpRoute {
    /// Generate Traefik IngressRouteTCP CRD YAML
    pub fn to_yaml(&self) -> String {
        let json = self.to_json();
        serde_yaml::to_string(&json).unwrap_or_default()
    }

    /// Generate Traefik IngressRouteTCP CRD JSON
    pub fn to_json(&self) -> serde_json::Value {
        let match_rule = if !self.sni_hosts.is_empty() {
            let sni_rules: Vec<String> = self
                .sni_hosts
                .iter()
                .map(|h| format!("HostSNI(`{}`)", h))
                .collect();
            sni_rules.join(" || ")
        } else if let Some(regex) = &self.sni_regex {
            format!("HostSNIRegexp(`{}`)", regex)
        } else {
            "HostSNI(`*`)".to_string()
        };

        let mut spec = json!({
            "entryPoints": [self.entrypoint],
            "routes": [{
                "match": match_rule,
                "services": [{
                    "name": self.service,
                    "port": self.port
                }]
            }]
        });

        if self.tls_passthrough {
            spec["tls"] = json!({ "passthrough": true });
        }

        json!({
            "apiVersion": "traefik.io/v1alpha1",
            "kind": "IngressRouteTCP",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "spec": spec
        })
    }
}

impl UdpRoute {
    /// Generate Traefik IngressRouteUDP CRD YAML
    pub fn to_yaml(&self) -> String {
        let json = self.to_json();
        serde_yaml::to_string(&json).unwrap_or_default()
    }

    /// Generate Traefik IngressRouteUDP CRD JSON
    pub fn to_json(&self) -> serde_json::Value {
        json!({
            "apiVersion": "traefik.io/v1alpha1",
            "kind": "IngressRouteUDP",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "spec": {
                "entryPoints": [self.entrypoint],
                "routes": [{
                    "services": [{
                        "name": self.service,
                        "port": self.port
                    }]
                }]
            }
        })
    }
}

impl Middleware {
    /// Generate Traefik Middleware CRD YAML
    pub fn to_yaml(&self) -> String {
        let json = self.to_json();
        serde_yaml::to_string(&json).unwrap_or_default()
    }

    /// Generate Traefik Middleware CRD JSON
    pub fn to_json(&self) -> serde_json::Value {
        let spec = match &self.spec {
            MiddlewareSpec::BasicAuth {
                secret,
                realm,
                remove_header,
            } => {
                let mut auth = json!({
                    "secret": secret,
                    "removeHeader": remove_header
                });
                if let Some(r) = realm {
                    auth["realm"] = json!(r);
                }
                json!({ "basicAuth": auth })
            }
            MiddlewareSpec::ForwardAuth {
                address,
                trust_forward_header,
                auth_response_headers,
                auth_request_headers,
            } => {
                let mut auth = json!({
                    "address": address,
                    "trustForwardHeader": trust_forward_header
                });
                if !auth_response_headers.is_empty() {
                    auth["authResponseHeaders"] = json!(auth_response_headers);
                }
                if !auth_request_headers.is_empty() {
                    auth["authRequestHeaders"] = json!(auth_request_headers);
                }
                json!({ "forwardAuth": auth })
            }
            MiddlewareSpec::RateLimit {
                average,
                burst,
                period,
                source_criterion,
            } => {
                let mut limit = json!({
                    "average": average,
                    "burst": burst,
                    "period": period
                });
                if let Some(criterion) = source_criterion {
                    let mut sc = json!({});
                    if let Some(ip_strategy) = &criterion.ip_strategy {
                        let mut ips = json!({});
                        if let Some(depth) = ip_strategy.depth {
                            ips["depth"] = json!(depth);
                        }
                        if !ip_strategy.excluded_ips.is_empty() {
                            ips["excludedIPs"] = json!(ip_strategy.excluded_ips);
                        }
                        sc["ipStrategy"] = ips;
                    }
                    if let Some(header) = &criterion.request_header_name {
                        sc["requestHeaderName"] = json!(header);
                    }
                    if criterion.request_host {
                        sc["requestHost"] = json!(true);
                    }
                    limit["sourceCriterion"] = sc;
                }
                json!({ "rateLimit": limit })
            }
            MiddlewareSpec::Headers {
                custom_request_headers,
                custom_response_headers,
                access_control_allow_origin,
                access_control_allow_methods,
                access_control_allow_headers,
                access_control_max_age,
                ssl_redirect,
                sts_seconds,
                sts_include_subdomains,
                frame_deny,
                content_type_nosniff,
                browser_xss_filter,
            } => {
                let mut headers = json!({});
                if !custom_request_headers.is_empty() {
                    headers["customRequestHeaders"] = json!(custom_request_headers);
                }
                if !custom_response_headers.is_empty() {
                    headers["customResponseHeaders"] = json!(custom_response_headers);
                }
                if let Some(origin) = access_control_allow_origin {
                    headers["accessControlAllowOriginList"] = json!([origin]);
                }
                if !access_control_allow_methods.is_empty() {
                    headers["accessControlAllowMethods"] = json!(access_control_allow_methods);
                }
                if !access_control_allow_headers.is_empty() {
                    headers["accessControlAllowHeaders"] = json!(access_control_allow_headers);
                }
                if let Some(max_age) = access_control_max_age {
                    headers["accessControlMaxAge"] = json!(max_age);
                }
                if *ssl_redirect {
                    headers["sslRedirect"] = json!(true);
                }
                if let Some(sts) = sts_seconds {
                    headers["stsSeconds"] = json!(sts);
                }
                if *sts_include_subdomains {
                    headers["stsIncludeSubdomains"] = json!(true);
                }
                if *frame_deny {
                    headers["frameDeny"] = json!(true);
                }
                if *content_type_nosniff {
                    headers["contentTypeNosniff"] = json!(true);
                }
                if *browser_xss_filter {
                    headers["browserXssFilter"] = json!(true);
                }
                json!({ "headers": headers })
            }
            MiddlewareSpec::StripPrefix { prefixes } => {
                json!({ "stripPrefix": { "prefixes": prefixes } })
            }
            MiddlewareSpec::AddPrefix { prefix } => {
                json!({ "addPrefix": { "prefix": prefix } })
            }
            MiddlewareSpec::RedirectScheme {
                scheme,
                permanent,
                port,
            } => {
                let mut redirect = json!({
                    "scheme": scheme,
                    "permanent": permanent
                });
                if let Some(p) = port {
                    redirect["port"] = json!(p);
                }
                json!({ "redirectScheme": redirect })
            }
            MiddlewareSpec::RedirectRegex {
                regex,
                replacement,
                permanent,
            } => {
                json!({
                    "redirectRegex": {
                        "regex": regex,
                        "replacement": replacement,
                        "permanent": permanent
                    }
                })
            }
            MiddlewareSpec::IpWhiteList {
                source_range,
                ip_strategy,
            } => {
                let mut whitelist = json!({
                    "sourceRange": source_range
                });
                if let Some(strategy) = ip_strategy {
                    let mut ips = json!({});
                    if let Some(depth) = strategy.depth {
                        ips["depth"] = json!(depth);
                    }
                    if !strategy.excluded_ips.is_empty() {
                        ips["excludedIPs"] = json!(strategy.excluded_ips);
                    }
                    whitelist["ipStrategy"] = ips;
                }
                json!({ "ipWhiteList": whitelist })
            }
            MiddlewareSpec::CircuitBreaker {
                expression,
                check_period,
                fallback_duration,
                recovery_duration,
            } => {
                let mut cb = json!({
                    "expression": expression
                });
                if let Some(period) = check_period {
                    cb["checkPeriod"] = json!(period);
                }
                if let Some(duration) = fallback_duration {
                    cb["fallbackDuration"] = json!(duration);
                }
                if let Some(duration) = recovery_duration {
                    cb["recoveryDuration"] = json!(duration);
                }
                json!({ "circuitBreaker": cb })
            }
            MiddlewareSpec::Retry {
                attempts,
                initial_interval,
            } => {
                let mut retry = json!({
                    "attempts": attempts
                });
                if let Some(interval) = initial_interval {
                    retry["initialInterval"] = json!(interval);
                }
                json!({ "retry": retry })
            }
            MiddlewareSpec::Compress {
                excluded_content_types,
                min_response_body_bytes,
            } => {
                let mut compress = json!({});
                if !excluded_content_types.is_empty() {
                    compress["excludedContentTypes"] = json!(excluded_content_types);
                }
                if let Some(bytes) = min_response_body_bytes {
                    compress["minResponseBodyBytes"] = json!(bytes);
                }
                json!({ "compress": compress })
            }
            MiddlewareSpec::Chain { middlewares } => {
                let refs: Vec<serde_json::Value> = middlewares
                    .iter()
                    .map(|m| json!({ "name": m }))
                    .collect();
                json!({ "chain": { "middlewares": refs } })
            }
            MiddlewareSpec::ReplacePath { path } => {
                json!({ "replacePath": { "path": path } })
            }
            MiddlewareSpec::ReplacePathRegex { regex, replacement } => {
                json!({
                    "replacePathRegex": {
                        "regex": regex,
                        "replacement": replacement
                    }
                })
            }
            MiddlewareSpec::Buffering {
                max_request_body_bytes,
                mem_request_body_bytes,
                max_response_body_bytes,
                mem_response_body_bytes,
                retry_expression,
            } => {
                let mut buf = json!({});
                if let Some(bytes) = max_request_body_bytes {
                    buf["maxRequestBodyBytes"] = json!(bytes);
                }
                if let Some(bytes) = mem_request_body_bytes {
                    buf["memRequestBodyBytes"] = json!(bytes);
                }
                if let Some(bytes) = max_response_body_bytes {
                    buf["maxResponseBodyBytes"] = json!(bytes);
                }
                if let Some(bytes) = mem_response_body_bytes {
                    buf["memResponseBodyBytes"] = json!(bytes);
                }
                if let Some(expr) = retry_expression {
                    buf["retryExpression"] = json!(expr);
                }
                json!({ "buffering": buf })
            }
            MiddlewareSpec::InFlightReq {
                amount,
                source_criterion,
            } => {
                let mut ifr = json!({
                    "amount": amount
                });
                if let Some(criterion) = source_criterion {
                    let mut sc = json!({});
                    if let Some(header) = &criterion.request_header_name {
                        sc["requestHeaderName"] = json!(header);
                    }
                    if criterion.request_host {
                        sc["requestHost"] = json!(true);
                    }
                    ifr["sourceCriterion"] = sc;
                }
                json!({ "inFlightReq": ifr })
            }
            MiddlewareSpec::Errors {
                status,
                service,
                query,
            } => {
                json!({
                    "errors": {
                        "status": status,
                        "service": {
                            "name": service
                        },
                        "query": query
                    }
                })
            }
        };

        json!({
            "apiVersion": "traefik.io/v1alpha1",
            "kind": "Middleware",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "spec": spec
        })
    }
}

impl TlsOption {
    /// Generate Traefik TLSOption CRD YAML
    pub fn to_yaml(&self) -> String {
        let json = self.to_json();
        serde_yaml::to_string(&json).unwrap_or_default()
    }

    /// Generate Traefik TLSOption CRD JSON
    pub fn to_json(&self) -> serde_json::Value {
        let mut spec = json!({});

        if let Some(min_ver) = &self.min_version {
            spec["minVersion"] = json!(min_ver);
        }
        if let Some(max_ver) = &self.max_version {
            spec["maxVersion"] = json!(max_ver);
        }
        if !self.cipher_suites.is_empty() {
            spec["cipherSuites"] = json!(self.cipher_suites);
        }
        if !self.curve_preferences.is_empty() {
            spec["curvePreferences"] = json!(self.curve_preferences);
        }
        if let Some(client_auth) = &self.client_auth {
            spec["clientAuth"] = json!({
                "secretNames": client_auth.ca_secrets,
                "clientAuthType": client_auth.client_auth_type
            });
        }
        if self.sni_strict {
            spec["sniStrict"] = json!(true);
        }
        if !self.alpn_protocols.is_empty() {
            spec["alpnProtocols"] = json!(self.alpn_protocols);
        }

        json!({
            "apiVersion": "traefik.io/v1alpha1",
            "kind": "TLSOption",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "spec": spec
        })
    }
}

// ============================================================================
// KubernetesManager Integration
// ============================================================================

impl KubernetesManager {
    /// Apply an HTTP route (IngressRoute) to the cluster
    pub async fn apply_traefik_http_route(&self, route: &HttpRoute) -> KubernetesResult<()> {
        self.apply_traefik_resource("IngressRoute", &route.name, &route.namespace, route.to_json())
            .await
    }

    /// Apply a TCP route (IngressRouteTCP) to the cluster
    pub async fn apply_traefik_tcp_route(&self, route: &TcpRoute) -> KubernetesResult<()> {
        self.apply_traefik_resource(
            "IngressRouteTCP",
            &route.name,
            &route.namespace,
            route.to_json(),
        )
        .await
    }

    /// Apply a UDP route (IngressRouteUDP) to the cluster
    pub async fn apply_traefik_udp_route(&self, route: &UdpRoute) -> KubernetesResult<()> {
        self.apply_traefik_resource(
            "IngressRouteUDP",
            &route.name,
            &route.namespace,
            route.to_json(),
        )
        .await
    }

    /// Apply a Middleware to the cluster
    pub async fn apply_traefik_middleware(&self, middleware: &Middleware) -> KubernetesResult<()> {
        self.apply_traefik_resource(
            "Middleware",
            &middleware.name,
            &middleware.namespace,
            middleware.to_json(),
        )
        .await
    }

    /// Apply a TLS option to the cluster
    pub async fn apply_traefik_tls_option(&self, option: &TlsOption) -> KubernetesResult<()> {
        self.apply_traefik_resource(
            "TLSOption",
            &option.name,
            &option.namespace,
            option.to_json(),
        )
        .await
    }

    /// Delete a Traefik HTTP route
    pub async fn delete_traefik_http_route(
        &self,
        name: &str,
        namespace: &str,
    ) -> KubernetesResult<()> {
        self.delete_traefik_resource("IngressRoute", name, namespace)
            .await
    }

    /// Delete a Traefik TCP route
    pub async fn delete_traefik_tcp_route(
        &self,
        name: &str,
        namespace: &str,
    ) -> KubernetesResult<()> {
        self.delete_traefik_resource("IngressRouteTCP", name, namespace)
            .await
    }

    /// Delete a Traefik UDP route
    pub async fn delete_traefik_udp_route(
        &self,
        name: &str,
        namespace: &str,
    ) -> KubernetesResult<()> {
        self.delete_traefik_resource("IngressRouteUDP", name, namespace)
            .await
    }

    /// Delete a Traefik Middleware
    pub async fn delete_traefik_middleware(
        &self,
        name: &str,
        namespace: &str,
    ) -> KubernetesResult<()> {
        self.delete_traefik_resource("Middleware", name, namespace)
            .await
    }

    /// Delete a Traefik TLS option
    pub async fn delete_traefik_tls_option(
        &self,
        name: &str,
        namespace: &str,
    ) -> KubernetesResult<()> {
        self.delete_traefik_resource("TLSOption", name, namespace)
            .await
    }

    /// List all Traefik HTTP routes in a namespace
    pub async fn list_traefik_http_routes(
        &self,
        namespace: &str,
    ) -> KubernetesResult<Vec<String>> {
        self.list_traefik_resources("IngressRoute", namespace).await
    }

    /// List all Traefik TCP routes in a namespace
    pub async fn list_traefik_tcp_routes(&self, namespace: &str) -> KubernetesResult<Vec<String>> {
        self.list_traefik_resources("IngressRouteTCP", namespace)
            .await
    }

    /// List all Traefik Middlewares in a namespace
    pub async fn list_traefik_middlewares(
        &self,
        namespace: &str,
    ) -> KubernetesResult<Vec<String>> {
        self.list_traefik_resources("Middleware", namespace).await
    }

    /// Internal helper to apply a Traefik CRD resource
    async fn apply_traefik_resource(
        &self,
        kind: &str,
        name: &str,
        namespace: &str,
        resource_json: serde_json::Value,
    ) -> KubernetesResult<()> {
        let api_resource = ApiResource {
            group: "traefik.io".to_string(),
            version: "v1alpha1".to_string(),
            api_version: "traefik.io/v1alpha1".to_string(),
            kind: kind.to_string(),
            plural: format!("{}s", kind.to_lowercase()),
        };

        let api: Api<DynamicObject> =
            Api::namespaced_with(self.client().clone(), namespace, &api_resource);

        let obj: DynamicObject = serde_json::from_value(resource_json).map_err(|e| {
            KubernetesError::operation_error(format!("Failed to deserialize resource: {}", e))
        })?;

        let patch_params = PatchParams::apply("sal-kubernetes").force();
        api.patch(name, &patch_params, &Patch::Apply(&obj))
            .await
            .map_err(|e| {
                KubernetesError::operation_error(format!(
                    "Failed to apply Traefik {} '{}': {}",
                    kind, name, e
                ))
            })?;

        log::info!("Applied Traefik {} '{}'", kind, name);
        Ok(())
    }

    /// Internal helper to delete a Traefik CRD resource
    async fn delete_traefik_resource(
        &self,
        kind: &str,
        name: &str,
        namespace: &str,
    ) -> KubernetesResult<()> {
        let api_resource = ApiResource {
            group: "traefik.io".to_string(),
            version: "v1alpha1".to_string(),
            api_version: "traefik.io/v1alpha1".to_string(),
            kind: kind.to_string(),
            plural: format!("{}s", kind.to_lowercase()),
        };

        let api: Api<DynamicObject> =
            Api::namespaced_with(self.client().clone(), namespace, &api_resource);

        api.delete(name, &Default::default()).await.map_err(|e| {
            KubernetesError::operation_error(format!(
                "Failed to delete Traefik {} '{}': {}",
                kind, name, e
            ))
        })?;

        log::info!("Deleted Traefik {} '{}'", kind, name);
        Ok(())
    }

    /// Internal helper to list Traefik CRD resources
    async fn list_traefik_resources(
        &self,
        kind: &str,
        namespace: &str,
    ) -> KubernetesResult<Vec<String>> {
        let api_resource = ApiResource {
            group: "traefik.io".to_string(),
            version: "v1alpha1".to_string(),
            api_version: "traefik.io/v1alpha1".to_string(),
            kind: kind.to_string(),
            plural: format!("{}s", kind.to_lowercase()),
        };

        let api: Api<DynamicObject> =
            Api::namespaced_with(self.client().clone(), namespace, &api_resource);

        let list = api
            .list(&Default::default())
            .await
            .map_err(|e| {
                KubernetesError::operation_error(format!(
                    "Failed to list Traefik {} resources: {}",
                    kind, e
                ))
            })?;

        let names: Vec<String> = list
            .items
            .iter()
            .filter_map(|obj| obj.metadata.name.clone())
            .collect();

        Ok(names)
    }
}

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

    #[test]
    fn test_http_route_builder() {
        let route = HttpRouteBuilder::new("my-app", "production")
            .hostname("app.example.com")
            .service("my-service", 8080)
            .build()
            .unwrap();

        assert_eq!(route.name, "my-app");
        assert_eq!(route.namespace, "production");
        assert_eq!(route.hostnames, vec!["app.example.com"]);
        assert_eq!(route.services.len(), 1);
        assert_eq!(route.services[0].name, "my-service");
        assert_eq!(route.services[0].port, 8080);
    }

    #[test]
    fn test_http_route_with_tls() {
        let route = HttpRouteBuilder::new("secure-app", "production")
            .hostname("secure.example.com")
            .service("my-service", 443)
            .tls_letsencrypt("letsencrypt")
            .build()
            .unwrap();

        assert!(route.tls.is_some());
        assert_eq!(
            route.tls.as_ref().unwrap().cert_resolver,
            Some("letsencrypt".to_string())
        );
    }

    #[test]
    fn test_weighted_services() {
        let route = HttpRouteBuilder::new("canary", "production")
            .hostname("app.example.com")
            .weighted_service("app-stable", 8080, 90)
            .weighted_service("app-canary", 8080, 10)
            .build()
            .unwrap();

        assert_eq!(route.services.len(), 2);
        assert_eq!(route.services[0].weight, Some(90));
        assert_eq!(route.services[1].weight, Some(10));
    }

    #[test]
    fn test_tcp_route_builder() {
        let route = TcpRouteBuilder::new("postgres", "databases")
            .entrypoint("postgres-tcp")
            .service("postgres-primary", 5432)
            .build()
            .unwrap();

        assert_eq!(route.name, "postgres");
        assert_eq!(route.entrypoint, "postgres-tcp");
        assert_eq!(route.service, "postgres-primary");
        assert_eq!(route.port, 5432);
    }

    #[test]
    fn test_middleware_basic_auth() {
        let middleware = MiddlewareBuilder::new("admin-auth", "production")
            .basic_auth("admin-credentials")
            .realm("Admin Area")
            .build();

        assert_eq!(middleware.name, "admin-auth");
        match middleware.spec {
            MiddlewareSpec::BasicAuth { secret, realm, .. } => {
                assert_eq!(secret, "admin-credentials");
                assert_eq!(realm, Some("Admin Area".to_string()));
            }
            _ => panic!("Expected BasicAuth middleware"),
        }
    }

    #[test]
    fn test_middleware_rate_limit() {
        let middleware = MiddlewareBuilder::new("api-rate-limit", "production")
            .rate_limit(100, 50)
            .period("1m")
            .build();

        match middleware.spec {
            MiddlewareSpec::RateLimit {
                average,
                burst,
                period,
                ..
            } => {
                assert_eq!(average, 100);
                assert_eq!(burst, 50);
                assert_eq!(period, "1m");
            }
            _ => panic!("Expected RateLimit middleware"),
        }
    }

    #[test]
    fn test_headers_security_defaults() {
        let middleware = MiddlewareBuilder::new("security", "production")
            .headers()
            .security_defaults()
            .build();

        match middleware.spec {
            MiddlewareSpec::Headers {
                frame_deny,
                content_type_nosniff,
                browser_xss_filter,
                sts_seconds,
                ..
            } => {
                assert!(frame_deny);
                assert!(content_type_nosniff);
                assert!(browser_xss_filter);
                assert_eq!(sts_seconds, Some(31536000));
            }
            _ => panic!("Expected Headers middleware"),
        }
    }

    #[test]
    fn test_http_route_to_json() {
        let route = HttpRouteBuilder::new("test-route", "default")
            .hostname("test.example.com")
            .service("test-service", 8080)
            .middleware("test-middleware")
            .build()
            .unwrap();

        let json = route.to_json();

        assert_eq!(json["apiVersion"], "traefik.io/v1alpha1");
        assert_eq!(json["kind"], "IngressRoute");
        assert_eq!(json["metadata"]["name"], "test-route");
        assert_eq!(json["metadata"]["namespace"], "default");
    }

    #[test]
    fn test_middleware_to_json() {
        let middleware = MiddlewareBuilder::new("redirect-https", "production")
            .redirect_scheme("https", true)
            .build();

        let json = middleware.to_json();

        assert_eq!(json["apiVersion"], "traefik.io/v1alpha1");
        assert_eq!(json["kind"], "Middleware");
        assert_eq!(json["spec"]["redirectScheme"]["scheme"], "https");
        assert_eq!(json["spec"]["redirectScheme"]["permanent"], true);
    }

    #[test]
    fn test_tls_option_builder() {
        let option = TlsOptionBuilder::new("strict-tls", "production")
            .min_version("VersionTLS12")
            .cipher_suites(vec![
                "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384".to_string(),
            ])
            .sni_strict(true)
            .build();

        assert_eq!(option.name, "strict-tls");
        assert_eq!(option.min_version, Some("VersionTLS12".to_string()));
        assert!(option.sni_strict);
    }
}
