use crate::core::logging::{redaction::RedactionConfig, writer::LogWriterConfig};

/// Log output format.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogFormat {
    /// Human-readable text logs.
    Text,
    /// Structured JSON logs.
    Json,
}

/// Span lifecycle events emitted by the formatter.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogSpanEvents {
    /// Do not emit span lifecycle events.
    None,
    /// Emit span close events.
    Close,
    /// Emit span creation and close events.
    NewAndClose,
    /// Emit all supported span lifecycle events.
    Full,
}

/// Logging configuration for rs-zero services.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogConfig {
    /// Env filter directive, for example `info,tower_http=debug`.
    pub filter: String,
    /// Whether ANSI colors should be emitted for terminal writers.
    pub ansi: bool,
    /// Output format.
    pub format: LogFormat,
    /// Whether tracing targets should be emitted.
    pub with_target: bool,
    /// Whether the current span should be included in JSON logs.
    pub include_current_span: bool,
    /// Whether the full span list should be included in JSON logs.
    pub include_span_list: bool,
    /// Span lifecycle event verbosity.
    pub span_events: LogSpanEvents,
    /// Optional logical service name.
    pub service: Option<String>,
    /// Writer configuration.
    pub writer: LogWriterConfig,
    /// Subscriber-layer redaction applied before records reach the writer.
    pub redaction: RedactionConfig,
}

impl Default for LogConfig {
    fn default() -> Self {
        Self {
            filter: "info".to_string(),
            ansi: true,
            format: LogFormat::Text,
            with_target: true,
            include_current_span: true,
            include_span_list: false,
            span_events: LogSpanEvents::Close,
            service: None,
            writer: LogWriterConfig::Stdout,
            redaction: RedactionConfig::default(),
        }
    }
}

impl LogConfig {
    /// Returns a config using `RUST_LOG` when available, otherwise `info`.
    pub fn from_env() -> Self {
        Self {
            filter: std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()),
            ..Self::default()
        }
    }

    /// Sets the output format.
    pub fn with_format(mut self, format: LogFormat) -> Self {
        self.format = format;
        self
    }

    /// Sets the logical service name.
    pub fn with_service(mut self, service: impl Into<String>) -> Self {
        self.service = Some(service.into());
        self
    }

    /// Sets the log writer.
    pub fn with_writer(mut self, writer: LogWriterConfig) -> Self {
        self.writer = writer;
        self
    }

    /// Sets subscriber-layer redaction.
    pub fn with_redaction(mut self, redaction: RedactionConfig) -> Self {
        self.redaction = redaction;
        self
    }
}
