use crate::observability::config::{LogFormat, LogLocalConfig};
use crate::observability::filter::SharedOrderedFilter;
use tracing_subscriber::{Layer, Registry};

/// Builds the stdout JSON layer.
///
/// This uses the same shared ordered filter as local file and remote outputs.
pub fn build_console_layer(
    format: LogFormat,
    filter: SharedOrderedFilter,
) -> Box<dyn Layer<Registry> + Send + Sync> {
    let base = tracing_subscriber::fmt::layer()
        .with_target(true)
        .with_file(true)
        .with_line_number(true)
        .with_thread_ids(true)
        .with_thread_names(true)
        .with_writer(std::io::stdout);

    match format {
        LogFormat::Json => base
            .json()
            .with_current_span(true)
            .with_span_list(true)
            .with_filter(filter)
            .boxed(),
        LogFormat::Compact => base.compact().with_filter(filter).boxed(),
        LogFormat::Full => base.with_filter(filter).boxed(),
        LogFormat::Pretty => base.pretty().with_filter(filter).boxed(),
    }
}

/// Builds the local rolling JSON file layer.
///
/// The supplied `filter` is the shared ordered filter used by all log outputs.
pub fn build_local_layer(
    config: &LogLocalConfig,
    format: LogFormat,
    filter: SharedOrderedFilter,
) -> (
    Box<dyn Layer<Registry> + Send + Sync>,
    tracing_appender::non_blocking::WorkerGuard,
) {
    let file_appender = tracing_appender::rolling::daily(&config.file_dir, &config.file_name);
    let (writer, guard) = tracing_appender::non_blocking(file_appender);

    let base = tracing_subscriber::fmt::layer()
        .with_target(true)
        .with_file(true)
        .with_line_number(true)
        .with_thread_ids(true)
        .with_thread_names(true)
        .with_writer(writer);

    let layer = match format {
        LogFormat::Json => base
            .json()
            .with_current_span(true)
            .with_span_list(true)
            .with_filter(filter)
            .boxed(),
        LogFormat::Compact => base.compact().with_filter(filter).boxed(),
        LogFormat::Full => base.with_filter(filter).boxed(),
        LogFormat::Pretty => base.pretty().with_filter(filter).boxed(),
    };

    (layer, guard)
}