use super::{FieldFilter, FuzzyFilter};
use crate::observability::config::{LogFilterConfig, LogFilterOverrideConfig};
use crate::observability::filter::fuzzy::TargetIndexRule;
use anyhow::{bail, Context as AnyhowContext, Result};
use parking_lot::RwLock;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use tracing::{field::Visit, Event, Level, Metadata, Subscriber};
use tracing_subscriber::{
    layer::{Context, Filter},
    registry::LookupSpan,
};

/// Override-based filter state.
///
/// Events that do not match an override use `default_level`. Events that match
/// one or more overrides use the highest-priority override, including its level
/// and field rules.
#[derive(Debug)]
pub struct OrderedFilter {
    default_level: LevelFilter,
    max_level: LevelFilter,
    overrides: Vec<CompiledOverride>,
    has_span_overrides: bool,
    target_index: TargetOverrideIndex,
    config: LogFilterConfig,
}

impl OrderedFilter {
    /// Builds and validates one override-based filter state.
    pub fn compile(config: LogFilterConfig) -> Result<Self> {
        let default_level = LevelFilter::parse(&config.default_level)?;
        validate_unique_override_names(&config.overrides)?;
        let mut overrides = config
            .overrides
            .clone()
            .into_iter()
            .filter(|config| config.enabled.unwrap_or(true))
            .map(CompiledOverride::compile)
            .collect::<Result<Vec<_>>>()?;
        overrides.sort_by(|left, right| right.priority.cmp(&left.priority));
        let max_level = overrides
            .iter()
            .map(|rule| rule.level)
            .fold(default_level, |max_level, level| max_level.max(level));
        let has_span_overrides = overrides.iter().any(CompiledOverride::needs_spans);
        let target_index = TargetOverrideIndex::compile(&overrides);

        Ok(Self {
            default_level,
            max_level,
            overrides,
            has_span_overrides,
            target_index,
            config,
        })
    }

    /// Returns the currently effective config snapshot.
    pub fn config(&self) -> LogFilterConfig {
        self.config.clone()
    }

    fn selected_override(&self, target: &str, spans: &[&str]) -> Option<&CompiledOverride> {
        self.overrides
            .iter()
            .find(|rule| rule.matches_target_or_span(target, spans))
    }

    fn selected_override_by_target(&self, target: &str) -> Option<&CompiledOverride> {
        if !self.target_index.has_indexed_rules() {
            return self
                .overrides
                .iter()
                .find(|rule| rule.matches_target(target));
        }

        self.target_index
            .selected_index(target, &self.overrides)
            .map(|index| &self.overrides[index])
    }
}

/// Shared reloadable ordered filter.
///
/// Clones of this type point at the same filter state. Attach the same clone to
/// local and remote layers to keep one global filter policy.
#[derive(Clone, Debug)]
pub struct SharedOrderedFilter {
    inner: Arc<RwLock<OrderedFilter>>,
}

impl SharedOrderedFilter {
    /// Compiles and creates a shared ordered filter.
    pub fn new(config: LogFilterConfig) -> Result<Self> {
        Ok(Self {
            inner: Arc::new(RwLock::new(OrderedFilter::compile(config)?)),
        })
    }

    /// Replaces the full filter state after successful validation.
    pub fn reload_filter(&self, config: LogFilterConfig) -> Result<()> {
        let next = OrderedFilter::compile(config)?;
        *self.inner.write() = next;
        tracing::callsite::rebuild_interest_cache();
        Ok(())
    }

    /// Replaces only the default log level.
    pub fn reload_default_level(&self, level: &str) -> Result<()> {
        let mut config = self.current_config();
        config.default_level = level.to_string();
        self.reload_filter(config)
    }

    /// Replaces only override rules.
    pub fn reload_overrides(
        &self,
        rules: Vec<crate::observability::config::LogFilterOverrideConfig>,
    ) -> Result<()> {
        let mut config = self.current_config();
        config.overrides = rules;
        self.reload_filter(config)
    }

    /// Enables or disables one override by name.
    pub fn set_override_enabled(&self, name: &str, enabled: bool) -> Result<()> {
        let mut config = self.current_config();
        let Some(rule) = config.overrides.iter_mut().find(|rule| rule.name == name) else {
            bail!("override rule `{}` not found", name);
        };
        rule.enabled = Some(enabled);
        self.reload_filter(config)
    }

    /// Returns the current effective filter config.
    pub fn current_config(&self) -> LogFilterConfig {
        self.inner.read().config()
    }

    /// Returns whether a synthetic JavaScript trace span should be recorded.
    ///
    /// This is intended for JS-owned spans created through the Rust native trace
    /// bridge. It evaluates the same ordered target/span level rules used by the
    /// tracing subscriber filter. Field rules are intentionally not evaluated
    /// here because span creation has no tracing event field visitor; JavaScript
    /// should use the exported filter snapshot to fail open when field rules are
    /// present.
    pub fn enabled_for_target_span(&self, level: &str, target: &str, span: &str) -> Result<bool> {
        let level = LevelFilter::parse(level)?;
        let guard = self.inner.read();
        if guard.overrides.is_empty() {
            return Ok(guard.default_level.allows_filter(level));
        }
        if !guard.max_level.allows_filter(level) {
            return Ok(false);
        }

        let selected = guard.selected_override(target, &[span]);
        if let Some(rule) = selected {
            return Ok(rule.level.allows_filter(level));
        }

        Ok(guard.default_level.allows_filter(level))
    }
}

impl<S> Filter<S> for SharedOrderedFilter
where
    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
{
    fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
        let guard = self.inner.read();
        if guard.overrides.is_empty() {
            return guard.default_level.allows(meta.level());
        }
        if !guard.max_level.allows(meta.level()) {
            return false;
        }
        // tracing-log emits the final event with a static `log` target and
        // stores the original log target in the event's `log.target` field.
        // Keep it until event_enabled can select the correct target override.
        if meta.target() == "log" {
            return true;
        }

        let selected = if guard.has_span_overrides {
            let spans = span_names(cx);
            guard.selected_override(meta.target(), &spans)
        } else {
            guard.selected_override_by_target(meta.target())
        };
        if let Some(rule) = selected {
            return rule.level.allows(meta.level());
        }

        guard.default_level.allows(meta.level())
    }

    fn event_enabled(&self, event: &Event<'_>, cx: &Context<'_, S>) -> bool {
        let guard = self.inner.read();
        let meta = event.metadata();
        if guard.overrides.is_empty() {
            return guard.default_level.allows(meta.level());
        }
        if !guard.max_level.allows(meta.level()) {
            return false;
        }
        let log_target = (meta.target() == "log")
            .then(|| log_record_target(event))
            .flatten();
        let target = log_target.as_deref().unwrap_or_else(|| meta.target());

        let selected = if guard.has_span_overrides {
            let spans = span_names(cx);
            guard.selected_override(target, &spans)
        } else {
            guard.selected_override_by_target(target)
        };
        if let Some(rule) = selected {
            if !rule.level.allows(meta.level()) {
                return false;
            }
            return rule
                .field_filter
                .as_ref()
                .map(|filter| filter.matches(event))
                .unwrap_or(true);
        }

        guard.default_level.allows(meta.level())
    }
}

fn log_record_target(event: &Event<'_>) -> Option<String> {
    let mut visitor = LogTargetVisitor::default();
    event.record(&mut visitor);
    visitor.target
}

#[derive(Default)]
struct LogTargetVisitor {
    target: Option<String>,
}

impl Visit for LogTargetVisitor {
    fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
        if field.name() == "log.target" {
            self.target = Some(value.to_string());
        }
    }

    fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
        if field.name() == "log.target" {
            self.target = Some(format!("{value:?}").trim_matches('"').to_string());
        }
    }
}

#[derive(Debug)]
struct CompiledOverride {
    level: LevelFilter,
    priority: i64,
    fuzzy_filter: Option<FuzzyFilter>,
    field_filter: Option<FieldFilter>,
}

impl CompiledOverride {
    fn compile(config: LogFilterOverrideConfig) -> Result<Self> {
        Ok(Self {
            level: LevelFilter::parse(&config.level)
                .with_context(|| format!("failed to compile override `{}` level", config.name))?,
            priority: config.priority,
            fuzzy_filter: FuzzyFilter::compile(config.fuzzy_rules).with_context(|| {
                format!("failed to compile override `{}` fuzzy_rules", config.name)
            })?,
            field_filter: FieldFilter::compile(config.field_rules).with_context(|| {
                format!("failed to compile override `{}` field_rules", config.name)
            })?,
        })
    }

    fn matches_target_or_span(&self, target: &str, spans: &[&str]) -> bool {
        self.fuzzy_filter
            .as_ref()
            .map(|filter| filter.matches(target, spans))
            .unwrap_or(true)
    }

    fn matches_target(&self, target: &str) -> bool {
        self.fuzzy_filter
            .as_ref()
            .map(|filter| filter.matches_target(target))
            .unwrap_or(true)
    }

    fn needs_spans(&self) -> bool {
        self.fuzzy_filter
            .as_ref()
            .map(FuzzyFilter::needs_spans)
            .unwrap_or(false)
    }

    fn target_index_rules(&self) -> Option<Vec<TargetIndexRule<'_>>> {
        self.fuzzy_filter
            .as_ref()
            .map(FuzzyFilter::target_index_rules)
            .unwrap_or_else(|| Some(Vec::new()))
    }
}

#[derive(Debug, Default)]
struct TargetOverrideIndex {
    exact: HashMap<String, usize>,
    prefixes_by_first_byte: HashMap<u8, Vec<(String, usize)>>,
    empty_prefixes: Vec<usize>,
    fallback: Vec<usize>,
}

impl TargetOverrideIndex {
    fn compile(overrides: &[CompiledOverride]) -> Self {
        let mut index = Self::default();
        for (override_index, rule) in overrides.iter().enumerate() {
            let Some(index_rules) = rule.target_index_rules() else {
                index.fallback.push(override_index);
                continue;
            };

            if index_rules.is_empty() {
                index.fallback.push(override_index);
                continue;
            }

            for index_rule in index_rules {
                match index_rule {
                    TargetIndexRule::Exact(pattern) => {
                        index
                            .exact
                            .entry(pattern.to_string())
                            .and_modify(|existing| *existing = (*existing).min(override_index))
                            .or_insert(override_index);
                    }
                    TargetIndexRule::Prefix(pattern) => {
                        if let Some(first_byte) = pattern.as_bytes().first().copied() {
                            index
                                .prefixes_by_first_byte
                                .entry(first_byte)
                                .or_default()
                                .push((pattern.to_string(), override_index));
                        } else {
                            index.empty_prefixes.push(override_index);
                        }
                    }
                }
            }
        }

        for prefixes in index.prefixes_by_first_byte.values_mut() {
            prefixes.sort_by(|left, right| {
                left.1
                    .cmp(&right.1)
                    .then_with(|| right.0.len().cmp(&left.0.len()))
            });
        }
        index.empty_prefixes.sort_unstable();
        index
    }

    fn has_indexed_rules(&self) -> bool {
        !self.exact.is_empty()
            || !self.prefixes_by_first_byte.is_empty()
            || !self.empty_prefixes.is_empty()
    }

    fn selected_index(&self, target: &str, overrides: &[CompiledOverride]) -> Option<usize> {
        let mut best = self.exact.get(target).copied();
        if best == Some(0) {
            return best;
        }

        if let Some(prefixes) = target
            .as_bytes()
            .first()
            .and_then(|first_byte| self.prefixes_by_first_byte.get(first_byte))
        {
            for (prefix, index) in prefixes {
                if best.is_some_and(|best| best <= *index) {
                    continue;
                }
                if target.starts_with(prefix) {
                    best = Some(*index);
                    if best == Some(0) {
                        return best;
                    }
                }
            }
        }

        for index in &self.empty_prefixes {
            if best.is_none_or(|best| *index < best) {
                best = Some(*index);
                if best == Some(0) {
                    return best;
                }
            }
        }

        for index in &self.fallback {
            if best.is_some_and(|best| best <= *index) {
                continue;
            }
            if overrides[*index].matches_target(target) {
                best = Some(*index);
                if best == Some(0) {
                    return best;
                }
            }
        }

        best
    }
}

fn validate_unique_override_names(rules: &[LogFilterOverrideConfig]) -> Result<()> {
    let mut names = HashSet::new();
    for rule in rules {
        if rule.name.trim().is_empty() {
            bail!("override rule name cannot be empty");
        }
        if !names.insert(rule.name.as_str()) {
            bail!("duplicate override rule name `{}`", rule.name);
        }
    }
    Ok(())
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum LevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl LevelFilter {
    fn parse(value: &str) -> Result<Self> {
        match value.to_ascii_lowercase().as_str() {
            "off" => Ok(Self::Off),
            "error" => Ok(Self::Error),
            "warn" | "warning" => Ok(Self::Warn),
            "info" => Ok(Self::Info),
            "debug" => Ok(Self::Debug),
            "trace" => Ok(Self::Trace),
            _ => bail!("unsupported log level `{}`", value),
        }
    }

    fn allows(self, level: &Level) -> bool {
        match self {
            Self::Off => false,
            Self::Error => *level <= Level::ERROR,
            Self::Warn => *level <= Level::WARN,
            Self::Info => *level <= Level::INFO,
            Self::Debug => *level <= Level::DEBUG,
            Self::Trace => *level <= Level::TRACE,
        }
    }

    fn allows_filter(self, level: LevelFilter) -> bool {
        match self {
            Self::Off => false,
            _ => level <= self,
        }
    }
}

fn span_names<'a, S>(cx: &'a Context<'_, S>) -> Vec<&'a str>
where
    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
{
    cx.lookup_current()
        .map(|span| span.scope().map(|span| span.name()).collect())
        .unwrap_or_default()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::observability::config::{
        FieldRuleConfig, FieldRuleOp, FuzzyMatchType, FuzzyRuleConfig, FuzzyRuleKind,
        LogFilterOverrideConfig,
    };
    use serde_json::json;
    use std::sync::{Arc, Mutex};
    use std::thread;
    use tracing::Dispatch;
    use tracing_subscriber::{layer::SubscriberExt, Layer};

    #[derive(Clone, Default)]
    struct RecordingLayer {
        events: Arc<Mutex<Vec<&'static str>>>,
    }

    impl RecordingLayer {
        fn events(&self) -> Vec<&'static str> {
            self.events.lock().unwrap().clone()
        }
    }

    impl<S> Layer<S> for RecordingLayer
    where
        S: Subscriber,
    {
        fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
            self.events.lock().unwrap().push(event.metadata().target());
        }
    }

    #[test]
    fn invalid_default_level_reload_keeps_old_config() {
        let filter = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: Vec::new(),
        })
        .unwrap();

        let err = filter.reload_default_level("not-a-level").unwrap_err();
        assert!(!err.to_string().is_empty());
        assert_eq!(filter.current_config().default_level, "info");
    }

    #[test]
    fn invalid_override_field_regex_reload_keeps_old_config() {
        let filter = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: Vec::new(),
        })
        .unwrap();

        let err = filter
            .reload_overrides(vec![LogFilterOverrideConfig {
                name: "bad_regex".to_string(),
                enabled: None,
                level: "debug".to_string(),
                priority: 100,
                fuzzy_rules: vec![FuzzyRuleConfig {
                    kind: FuzzyRuleKind::Target,
                    match_type: FuzzyMatchType::Contains,
                    pattern: "decoder".to_string(),
                    level: None,
                }],
                field_rules: vec![FieldRuleConfig {
                    field: "msg".to_string(),
                    op: FieldRuleOp::Regex,
                    value: json!("("),
                }],
            }])
            .unwrap_err();

        let error_chain = format!("{:#}", err);
        assert!(error_chain.contains("regex parse error"));
        assert!(error_chain.contains("bad_regex"));
        assert!(filter.current_config().overrides.is_empty());
    }

    #[test]
    fn duplicate_override_names_fail_compile() {
        let err = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule("same"), override_rule("same")],
        })
        .unwrap_err();

        assert!(err
            .to_string()
            .contains("duplicate override rule name `same`"));
    }

    #[test]
    fn set_override_enabled_updates_rule_by_name() {
        let filter = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule("decoder_debug")],
        })
        .unwrap();

        filter.set_override_enabled("decoder_debug", false).unwrap();
        assert_eq!(filter.current_config().overrides[0].enabled, Some(false));

        let err = filter.set_override_enabled("missing", true).unwrap_err();
        assert!(err
            .to_string()
            .contains("override rule `missing` not found"));
    }

    #[test]
    fn end_to_end_reload_default_level_changes_event_filtering() {
        let layer = RecordingLayer::default();
        let filter = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: Vec::new(),
        })
        .unwrap();
        let dispatch = Dispatch::new(
            tracing_subscriber::registry().with(layer.clone().with_filter(filter.clone())),
        );

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::debug!(target: "app::reload", "blocked before reload");
        });
        filter.reload_default_level("debug").unwrap();
        tracing::dispatcher::with_default(&dispatch, || {
            tracing::debug!(target: "app::reload", "allowed after reload");
        });

        assert_eq!(layer.events(), vec!["app::reload"]);
    }

    #[test]
    fn concurrent_filter_reads_and_reload_do_not_panic() {
        let filter = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule_with_match(
                "decoder_debug",
                100,
                FuzzyMatchType::Exact,
                "app::decoder",
            )],
        })
        .unwrap();

        let mut workers = Vec::new();
        for _ in 0..4 {
            let filter = filter.clone();
            workers.push(thread::spawn(move || {
                for _ in 0..100 {
                    let _ = filter.current_config();
                }
            }));
        }

        for index in 0..100 {
            filter
                .reload_default_level(if index % 2 == 0 { "debug" } else { "info" })
                .unwrap();
        }

        for worker in workers {
            worker.join().unwrap();
        }
    }

    #[test]
    fn end_to_end_default_level_and_target_override_filter_events() {
        let (dispatch, layer) = dispatch_with_filter(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule_with_match(
                "decoder_debug",
                100,
                FuzzyMatchType::Exact,
                "app::decoder",
            )],
        });

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::debug!(target: "app::other", "default info blocks debug");
            tracing::info!(target: "app::other", "default info allows info");
            tracing::debug!(target: "app::decoder", "override allows debug");
        });

        assert_eq!(layer.events(), vec!["app::other", "app::decoder"]);
    }

    #[test]
    fn end_to_end_log_record_uses_original_target_for_override() {
        let (dispatch, layer) = dispatch_with_filter(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule_with_match(
                "log_decoder_debug",
                100,
                FuzzyMatchType::Exact,
                "app::decoder",
            )],
        });

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::event!(
                target: "log",
                Level::DEBUG,
                log.target = "app::other",
                "blocked by default info"
            );
            tracing::event!(
                target: "log",
                Level::DEBUG,
                log.target = "app::decoder",
                "allowed by original log target override"
            );
        });

        assert_eq!(layer.events(), vec!["log"]);
    }

    #[test]
    fn end_to_end_reload_enables_log_record_target_debug() {
        let layer = RecordingLayer::default();
        let filter = SharedOrderedFilter::new(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: Vec::new(),
        })
        .unwrap();
        let dispatch = Dispatch::new(
            tracing_subscriber::registry().with(layer.clone().with_filter(filter.clone())),
        );

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::event!(
                target: "log",
                Level::DEBUG,
                log.target = "app::decoder",
                "blocked before reload"
            );
        });
        filter
            .reload_overrides(vec![override_rule_with_match(
                "log_decoder_debug",
                100,
                FuzzyMatchType::Exact,
                "app::decoder",
            )])
            .unwrap();
        tracing::dispatcher::with_default(&dispatch, || {
            tracing::event!(
                target: "log",
                Level::DEBUG,
                log.target = "app::decoder",
                "allowed after reload"
            );
        });

        assert_eq!(layer.events(), vec!["log"]);
    }

    #[test]
    fn end_to_end_high_priority_off_blocks_lower_priority_rule() {
        let (dispatch, layer) = dispatch_with_filter(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![
                override_rule_with_level_and_priority(
                    "decoder_off",
                    "off",
                    200,
                    FuzzyMatchType::Exact,
                    "app::decoder",
                    Vec::new(),
                ),
                override_rule_with_level_and_priority(
                    "decoder_debug",
                    "debug",
                    100,
                    FuzzyMatchType::Exact,
                    "app::decoder",
                    Vec::new(),
                ),
            ],
        });

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::info!(target: "app::decoder", "high priority off blocks info");
            tracing::debug!(target: "app::decoder", "high priority off blocks debug");
        });

        assert!(layer.events().is_empty());
    }

    #[test]
    fn end_to_end_field_mismatch_blocks_lower_priority_rule() {
        let field_rule = FieldRuleConfig {
            field: "id".to_string(),
            op: FieldRuleOp::Eq,
            value: json!(100),
        };
        let (dispatch, layer) = dispatch_with_filter(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![
                override_rule_with_level_and_priority(
                    "decoder_id_100",
                    "debug",
                    200,
                    FuzzyMatchType::Exact,
                    "app::decoder",
                    vec![field_rule],
                ),
                override_rule_with_level_and_priority(
                    "decoder_debug",
                    "debug",
                    100,
                    FuzzyMatchType::Exact,
                    "app::decoder",
                    Vec::new(),
                ),
            ],
        });

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::debug!(target: "app::decoder", id = 101_u64, "field mismatch");
            tracing::debug!(target: "app::decoder", id = 100_u64, "field match");
        });

        assert_eq!(layer.events(), vec!["app::decoder"]);
    }

    #[test]
    fn end_to_end_span_rule_filters_events_inside_matching_span() {
        let (dispatch, layer) = dispatch_with_filter(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule_with_span(
                "decode_span_debug",
                "debug",
                100,
                FuzzyMatchType::Contains,
                "decode",
            )],
        });

        tracing::dispatcher::with_default(&dispatch, || {
            tracing::debug!(target: "app::decoder", "outside span");
            let span = tracing::info_span!("decode_transaction");
            let _entered = span.enter();
            tracing::debug!(target: "app::decoder", "inside matching span");
        });

        assert_eq!(layer.events(), vec!["app::decoder"]);
    }

    #[test]
    fn target_index_preserves_priority_across_indexed_and_fallback_rules() {
        let high_fallback =
            override_rule_with_match("high_fallback", 200, FuzzyMatchType::Contains, "decoder");
        let middle_exact =
            override_rule_with_match("middle_exact", 100, FuzzyMatchType::Exact, "app::decoder");
        let low_prefix =
            override_rule_with_match("low_prefix", 50, FuzzyMatchType::Prefix, "app::");
        let filter = OrderedFilter::compile(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![low_prefix, middle_exact, high_fallback],
        })
        .unwrap();

        let selected = filter.selected_override_by_target("app::decoder").unwrap();
        assert_eq!(selected.priority, 200);

        let selected = filter.selected_override_by_target("app::worker").unwrap();
        assert_eq!(selected.priority, 50);

        assert!(filter.selected_override_by_target("other").is_none());
    }

    #[test]
    fn target_index_matches_linear_target_selection_for_mixed_rules() {
        let filter = OrderedFilter::compile(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![
                override_rule_with_match("prefix_app", 110, FuzzyMatchType::Prefix, "app::"),
                override_rule_with_match(
                    "exact_decoder",
                    100,
                    FuzzyMatchType::Exact,
                    "app::decoder",
                ),
                override_rule_with_match("contains_cache", 90, FuzzyMatchType::Contains, "cache"),
                override_rule_with_match("prefix_worker", 80, FuzzyMatchType::Prefix, "worker::"),
                override_rule_with_match("exact_empty", 70, FuzzyMatchType::Exact, ""),
                override_rule_with_match("prefix_empty", 60, FuzzyMatchType::Prefix, ""),
            ],
        })
        .unwrap();

        for target in [
            "app::decoder",
            "app::cache",
            "worker::cache",
            "other::cache",
            "nothing",
            "",
        ] {
            let indexed = filter
                .selected_override_by_target(target)
                .map(|rule| rule.priority);
            let linear =
                linear_selected_override_by_target(&filter, target).map(|rule| rule.priority);
            assert_eq!(
                indexed, linear,
                "target `{target}` should match linear scan"
            );
        }
    }

    #[test]
    fn max_level_tracks_default_and_override_levels() {
        let filter = OrderedFilter::compile(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![override_rule_with_level(
                "decoder_trace",
                "trace",
                FuzzyMatchType::Exact,
                "app::decoder",
            )],
        })
        .unwrap();

        assert!(filter.max_level.allows(&Level::TRACE));

        let filter = OrderedFilter::compile(LogFilterConfig {
            default_level: "warn".to_string(),
            overrides: vec![override_rule_with_level(
                "decoder_off",
                "off",
                FuzzyMatchType::Exact,
                "app::decoder",
            )],
        })
        .unwrap();

        assert!(!filter.max_level.allows(&Level::INFO));
        assert!(filter.max_level.allows(&Level::WARN));
    }

    #[test]
    fn prefix_index_checks_only_relevant_prefix_bucket() {
        let filter = OrderedFilter::compile(LogFilterConfig {
            default_level: "info".to_string(),
            overrides: vec![
                override_rule_with_match("alpha", 100, FuzzyMatchType::Prefix, "alpha::"),
                override_rule_with_match("beta", 90, FuzzyMatchType::Prefix, "beta::"),
            ],
        })
        .unwrap();

        let selected = filter.selected_override_by_target("beta::worker").unwrap();
        assert_eq!(selected.priority, 90);
        assert!(filter
            .selected_override_by_target("gamma::worker")
            .is_none());
    }

    fn override_rule(name: &str) -> LogFilterOverrideConfig {
        override_rule_with_match(name, 100, FuzzyMatchType::Contains, "decoder")
    }

    fn override_rule_with_match(
        name: &str,
        priority: i64,
        match_type: FuzzyMatchType,
        pattern: &str,
    ) -> LogFilterOverrideConfig {
        override_rule_with_level_and_priority(
            name,
            "debug",
            priority,
            match_type,
            pattern,
            Vec::new(),
        )
    }

    fn override_rule_with_level(
        name: &str,
        level: &str,
        match_type: FuzzyMatchType,
        pattern: &str,
    ) -> LogFilterOverrideConfig {
        override_rule_with_level_and_priority(name, level, 100, match_type, pattern, Vec::new())
    }

    fn override_rule_with_level_and_priority(
        name: &str,
        level: &str,
        priority: i64,
        match_type: FuzzyMatchType,
        pattern: &str,
        field_rules: Vec<FieldRuleConfig>,
    ) -> LogFilterOverrideConfig {
        LogFilterOverrideConfig {
            name: name.to_string(),
            enabled: None,
            level: level.to_string(),
            priority,
            fuzzy_rules: vec![FuzzyRuleConfig {
                kind: FuzzyRuleKind::Target,
                match_type,
                pattern: pattern.to_string(),
                level: None,
            }],
            field_rules,
        }
    }

    fn override_rule_with_span(
        name: &str,
        level: &str,
        priority: i64,
        match_type: FuzzyMatchType,
        pattern: &str,
    ) -> LogFilterOverrideConfig {
        LogFilterOverrideConfig {
            name: name.to_string(),
            enabled: None,
            level: level.to_string(),
            priority,
            fuzzy_rules: vec![FuzzyRuleConfig {
                kind: FuzzyRuleKind::Span,
                match_type,
                pattern: pattern.to_string(),
                level: None,
            }],
            field_rules: Vec::new(),
        }
    }

    fn dispatch_with_filter(config: LogFilterConfig) -> (Dispatch, RecordingLayer) {
        let layer = RecordingLayer::default();
        let filter = SharedOrderedFilter::new(config).unwrap();
        let dispatch =
            Dispatch::new(tracing_subscriber::registry().with(layer.clone().with_filter(filter)));
        (dispatch, layer)
    }

    fn linear_selected_override_by_target<'a>(
        filter: &'a OrderedFilter,
        target: &str,
    ) -> Option<&'a CompiledOverride> {
        filter
            .overrides
            .iter()
            .find(|rule| rule.matches_target(target))
    }
}
