//! Authentication Metrics for 6-Layer Security
//!
//! Tracks performance and errors for:
//! - JWT extraction and validation
//! - Revocation checking (Redis)
//! - RBAC permission checks (cached)
//! - Rate limiting (token bucket)
//! - MFA verification
//! - Audit logging

use prometheus::{Counter, CounterVec, Histogram, HistogramOpts, IntGauge, Opts, Registry};

/// Authentication metrics for all 6 layers
pub struct AuthMetrics {
    // === Request Counters ===
    /// Total authentication requests
    pub auth_requests_total: Counter,
    /// Successful authentications
    pub auth_requests_success: Counter,
    /// Failed authentications
    pub auth_requests_failure: Counter,

    // === Layer-Specific Latencies (microseconds) ===
    /// JWT extraction and parsing latency
    pub jwt_extraction_duration_us: Histogram,
    /// JWT signature validation latency
    pub jwt_validation_duration_us: Histogram,
    /// JWT revocation check latency (Redis)
    pub revocation_check_duration_us: Histogram,
    /// RBAC permission check latency
    pub rbac_check_duration_us: Histogram,
    /// Rate limit check latency
    pub rate_limit_check_duration_us: Histogram,
    /// MFA verification latency (TOTP)
    pub mfa_verification_duration_us: Histogram,
    /// Total auth pipeline latency
    pub auth_total_duration_us: Histogram,

    // === Error Counters by Type ===
    /// Missing Authorization header
    pub auth_errors_missing_jwt: Counter,
    /// Malformed JWT token
    pub auth_errors_invalid_jwt: Counter,
    /// JWT signature verification failed
    pub auth_errors_signature_failed: Counter,
    /// JWT expired
    pub auth_errors_expired_jwt: Counter,
    /// JWT revoked (blacklisted)
    pub auth_errors_revoked_jwt: Counter,
    /// RBAC permission denied
    pub auth_errors_permission_denied: Counter,
    /// Rate limit exceeded
    pub auth_errors_rate_limited: Counter,
    /// MFA verification failed
    pub auth_errors_mfa_failed: Counter,
    /// Redis connection errors
    pub auth_errors_redis_failure: Counter,

    // === Current State Gauges ===
    /// Number of active JWT tokens (estimated)
    pub active_jwt_tokens: IntGauge,
    /// Number of revoked tokens in cache
    pub revoked_tokens_cached: IntGauge,
    /// RBAC permission cache size
    pub rbac_cache_size: IntGauge,
    /// Rate limiter entries
    pub rate_limiter_entries: IntGauge,

    // === Per-User Metrics ===
    /// Requests per user (labeled by user_id)
    pub requests_by_user: CounterVec,
    /// Auth failures per user
    pub auth_failures_by_user: CounterVec,
    /// Rate limit hits per user
    pub rate_limits_by_user: CounterVec,

    // === Cache Performance ===
    /// JWT decoding key cache hits
    pub jwt_cache_hits: Counter,
    /// JWT decoding key cache misses
    pub jwt_cache_misses: Counter,
    /// RBAC permission cache hits
    pub rbac_cache_hits: Counter,
    /// RBAC permission cache misses
    pub rbac_cache_misses: Counter,

    // === Performance Targets ===
    /// Counter for auth requests meeting <10μs SLA
    pub auth_sla_met: Counter,
    /// Counter for auth requests exceeding <10μs SLA
    pub auth_sla_exceeded: Counter,
}

impl AuthMetrics {
    /// Create new authentication metrics and register with Prometheus
    pub fn new(registry: &Registry) -> Result<Self, prometheus::Error> {
        // === Request Counters ===
        let auth_requests_total = Counter::with_opts(Opts::new(
            "api_auth_requests_total",
            "Total authentication requests",
        ))?;
        registry.register(Box::new(auth_requests_total.clone()))?;

        let auth_requests_success = Counter::with_opts(Opts::new(
            "api_auth_requests_success",
            "Successful authentication requests",
        ))?;
        registry.register(Box::new(auth_requests_success.clone()))?;

        let auth_requests_failure = Counter::with_opts(Opts::new(
            "api_auth_requests_failure",
            "Failed authentication requests",
        ))?;
        registry.register(Box::new(auth_requests_failure.clone()))?;

        // === Layer-Specific Latencies (microseconds) ===
        // Buckets: 0.1, 0.5, 1, 2, 5, 10, 20, 50, 100 microseconds
        let latency_buckets = vec![0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0, 100.0];

        let jwt_extraction_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_jwt_extraction_duration_microseconds",
                "JWT extraction and parsing latency in microseconds",
            )
            .buckets(latency_buckets.clone()),
        )?;
        registry.register(Box::new(jwt_extraction_duration_us.clone()))?;

        let jwt_validation_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_jwt_validation_duration_microseconds",
                "JWT signature validation latency in microseconds",
            )
            .buckets(latency_buckets.clone()),
        )?;
        registry.register(Box::new(jwt_validation_duration_us.clone()))?;

        let revocation_check_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_revocation_check_duration_microseconds",
                "JWT revocation check latency in microseconds (Redis)",
            )
            .buckets(latency_buckets),
        )?;
        registry.register(Box::new(revocation_check_duration_us.clone()))?;

        let rbac_check_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_rbac_check_duration_microseconds",
                "RBAC permission check latency in microseconds",
            )
            .buckets(vec![0.05, 0.1, 0.2, 0.5, 1.0, 2.0, 5.0]), // Sub-microsecond buckets
        )?;
        registry.register(Box::new(rbac_check_duration_us.clone()))?;

        let rate_limit_check_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_rate_limit_check_duration_microseconds",
                "Rate limit check latency in microseconds",
            )
            .buckets(vec![0.01, 0.05, 0.1, 0.2, 0.5, 1.0]), // Ultra-fast atomic operations
        )?;
        registry.register(Box::new(rate_limit_check_duration_us.clone()))?;

        let mfa_verification_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_mfa_verification_duration_microseconds",
                "MFA (TOTP) verification latency in microseconds",
            )
            .buckets(vec![10.0, 50.0, 100.0, 500.0, 1000.0]), // TOTP is slower
        )?;
        registry.register(Box::new(mfa_verification_duration_us.clone()))?;

        let auth_total_duration_us = Histogram::with_opts(
            HistogramOpts::new(
                "api_auth_total_duration_microseconds",
                "Total authentication pipeline latency in microseconds",
            )
            .buckets(vec![1.0, 5.0, 10.0, 20.0, 50.0, 100.0, 200.0, 500.0]),
        )?;
        registry.register(Box::new(auth_total_duration_us.clone()))?;

        // === Error Counters ===
        let auth_errors_missing_jwt = Counter::with_opts(Opts::new(
            "api_auth_errors_missing_jwt",
            "Missing Authorization header errors",
        ))?;
        registry.register(Box::new(auth_errors_missing_jwt.clone()))?;

        let auth_errors_invalid_jwt = Counter::with_opts(Opts::new(
            "api_auth_errors_invalid_jwt",
            "Malformed JWT token errors",
        ))?;
        registry.register(Box::new(auth_errors_invalid_jwt.clone()))?;

        let auth_errors_signature_failed = Counter::with_opts(Opts::new(
            "api_auth_errors_signature_failed",
            "JWT signature verification failures",
        ))?;
        registry.register(Box::new(auth_errors_signature_failed.clone()))?;

        let auth_errors_expired_jwt = Counter::with_opts(Opts::new(
            "api_auth_errors_expired_jwt",
            "Expired JWT token errors",
        ))?;
        registry.register(Box::new(auth_errors_expired_jwt.clone()))?;

        let auth_errors_revoked_jwt = Counter::with_opts(Opts::new(
            "api_auth_errors_revoked_jwt",
            "Revoked JWT token errors (blacklisted)",
        ))?;
        registry.register(Box::new(auth_errors_revoked_jwt.clone()))?;

        let auth_errors_permission_denied = Counter::with_opts(Opts::new(
            "api_auth_errors_permission_denied",
            "RBAC permission denied errors",
        ))?;
        registry.register(Box::new(auth_errors_permission_denied.clone()))?;

        let auth_errors_rate_limited = Counter::with_opts(Opts::new(
            "api_auth_errors_rate_limited",
            "Rate limit exceeded errors",
        ))?;
        registry.register(Box::new(auth_errors_rate_limited.clone()))?;

        let auth_errors_mfa_failed = Counter::with_opts(Opts::new(
            "api_auth_errors_mfa_failed",
            "MFA verification failures",
        ))?;
        registry.register(Box::new(auth_errors_mfa_failed.clone()))?;

        let auth_errors_redis_failure = Counter::with_opts(Opts::new(
            "api_auth_errors_redis_failure",
            "Redis connection/operation failures",
        ))?;
        registry.register(Box::new(auth_errors_redis_failure.clone()))?;

        // === Current State Gauges ===
        let active_jwt_tokens = IntGauge::with_opts(Opts::new(
            "api_active_jwt_tokens",
            "Number of active JWT tokens (estimated)",
        ))?;
        registry.register(Box::new(active_jwt_tokens.clone()))?;

        let revoked_tokens_cached = IntGauge::with_opts(Opts::new(
            "api_revoked_tokens_cached",
            "Number of revoked tokens in Redis cache",
        ))?;
        registry.register(Box::new(revoked_tokens_cached.clone()))?;

        let rbac_cache_size = IntGauge::with_opts(Opts::new(
            "api_rbac_cache_size",
            "RBAC permission cache entries",
        ))?;
        registry.register(Box::new(rbac_cache_size.clone()))?;

        let rate_limiter_entries = IntGauge::with_opts(Opts::new(
            "api_rate_limiter_entries",
            "Rate limiter tracked users",
        ))?;
        registry.register(Box::new(rate_limiter_entries.clone()))?;

        // === Per-User Metrics ===
        let requests_by_user = CounterVec::new(
            Opts::new("api_requests_by_user", "Requests per user"),
            &["user_id"],
        )?;
        registry.register(Box::new(requests_by_user.clone()))?;

        let auth_failures_by_user = CounterVec::new(
            Opts::new(
                "api_auth_failures_by_user",
                "Auth failures per user",
            ),
            &["user_id", "reason"],
        )?;
        registry.register(Box::new(auth_failures_by_user.clone()))?;

        let rate_limits_by_user = CounterVec::new(
            Opts::new(
                "api_rate_limits_by_user",
                "Rate limit hits per user",
            ),
            &["user_id"],
        )?;
        registry.register(Box::new(rate_limits_by_user.clone()))?;

        // === Cache Performance ===
        let jwt_cache_hits = Counter::with_opts(Opts::new(
            "api_jwt_cache_hits",
            "JWT decoding key cache hits",
        ))?;
        registry.register(Box::new(jwt_cache_hits.clone()))?;

        let jwt_cache_misses = Counter::with_opts(Opts::new(
            "api_jwt_cache_misses",
            "JWT decoding key cache misses",
        ))?;
        registry.register(Box::new(jwt_cache_misses.clone()))?;

        let rbac_cache_hits = Counter::with_opts(Opts::new(
            "api_rbac_cache_hits",
            "RBAC permission cache hits",
        ))?;
        registry.register(Box::new(rbac_cache_hits.clone()))?;

        let rbac_cache_misses = Counter::with_opts(Opts::new(
            "api_rbac_cache_misses",
            "RBAC permission cache misses",
        ))?;
        registry.register(Box::new(rbac_cache_misses.clone()))?;

        // === Performance SLA ===
        let auth_sla_met = Counter::with_opts(Opts::new(
            "api_auth_sla_met",
            "Auth requests meeting <10μs SLA",
        ))?;
        registry.register(Box::new(auth_sla_met.clone()))?;

        let auth_sla_exceeded = Counter::with_opts(Opts::new(
            "api_auth_sla_exceeded",
            "Auth requests exceeding <10μs SLA",
        ))?;
        registry.register(Box::new(auth_sla_exceeded.clone()))?;

        Ok(Self {
            auth_requests_total,
            auth_requests_success,
            auth_requests_failure,
            jwt_extraction_duration_us,
            jwt_validation_duration_us,
            revocation_check_duration_us,
            rbac_check_duration_us,
            rate_limit_check_duration_us,
            mfa_verification_duration_us,
            auth_total_duration_us,
            auth_errors_missing_jwt,
            auth_errors_invalid_jwt,
            auth_errors_signature_failed,
            auth_errors_expired_jwt,
            auth_errors_revoked_jwt,
            auth_errors_permission_denied,
            auth_errors_rate_limited,
            auth_errors_mfa_failed,
            auth_errors_redis_failure,
            active_jwt_tokens,
            revoked_tokens_cached,
            rbac_cache_size,
            rate_limiter_entries,
            requests_by_user,
            auth_failures_by_user,
            rate_limits_by_user,
            jwt_cache_hits,
            jwt_cache_misses,
            rbac_cache_hits,
            rbac_cache_misses,
            auth_sla_met,
            auth_sla_exceeded,
        })
    }

    /// Record successful authentication with latency breakdown
    pub fn record_success(&self, total_duration_us: f64) {
        self.auth_requests_total.inc();
        self.auth_requests_success.inc();
        self.auth_total_duration_us.observe(total_duration_us);

        // Check SLA: <10μs target
        if total_duration_us < 10.0 {
            self.auth_sla_met.inc();
        } else {
            self.auth_sla_exceeded.inc();
        }
    }

    /// Record authentication failure with reason
    pub fn record_failure(&self, reason: &str, user_id: Option<&str>) {
        self.auth_requests_total.inc();
        self.auth_requests_failure.inc();

        // Increment specific error counter
        match reason {
            "missing_jwt" => self.auth_errors_missing_jwt.inc(),
            "invalid_jwt" => self.auth_errors_invalid_jwt.inc(),
            "signature_failed" => self.auth_errors_signature_failed.inc(),
            "expired_jwt" => self.auth_errors_expired_jwt.inc(),
            "revoked_jwt" => self.auth_errors_revoked_jwt.inc(),
            "permission_denied" => self.auth_errors_permission_denied.inc(),
            "rate_limited" => self.auth_errors_rate_limited.inc(),
            "mfa_failed" => self.auth_errors_mfa_failed.inc(),
            "redis_failure" => self.auth_errors_redis_failure.inc(),
            _ => {}, // Unknown error type
        }

        // Track per-user failures
        if let Some(uid) = user_id {
            self.auth_failures_by_user
                .with_label_values(&[uid, reason])
                .inc();
        }
    }

    /// Record per-user request
    pub fn record_user_request(&self, user_id: &str) {
        self.requests_by_user.with_label_values(&[user_id]).inc();
    }

    /// Record rate limit hit for user
    pub fn record_rate_limit(&self, user_id: &str) {
        self.rate_limits_by_user.with_label_values(&[user_id]).inc();
    }
}
