// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

#[cfg(test)]
mod tests {
    use psmatcher::{event_types::*, *};

    #[test]
    fn test_simple_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a subscription for weather updates in San Francisco
        let subscription = Subscription::new("weather-sf")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("weather".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "city".to_string(),
                    value: AttributeValue::String("San Francisco".to_string()),
                },
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(subscription);

        // Create a matching event
        let matching_event = DefaultEvent::new("weather")
            .with_attribute("city", AttributeValue::String("San Francisco".to_string()))
            .with_attribute("temperature", AttributeValue::Float(72.5));

        // Create a non-matching event (different city)
        let non_matching_event = DefaultEvent::new("weather")
            .with_attribute("city", AttributeValue::String("New York".to_string()))
            .with_attribute("temperature".to_string(), AttributeValue::Float(65.0));

        // Match the events against subscriptions
        let matches1 = matcher.match_event(&matching_event).unwrap();
        let matches2 = matcher.match_event(&non_matching_event).unwrap();

        // Check if our subscription matched correctly
        assert!(matches1.contains("weather-sf"));
        assert!(!matches2.contains("weather-sf"));
    }

    #[test]
    fn test_complex_predicates() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a subscription for high temperature alerts
        let subscription = Subscription::new("high-temp-alert")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("weather".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::GreaterThan {
                    attribute: "temperature".to_string(),
                    value: 90.0,
                },
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(subscription);

        // Create events with different temperatures
        let high_temp_event =
            DefaultEvent::new("weather").with_attribute("temperature", AttributeValue::Float(95.0));

        let low_temp_event =
            DefaultEvent::new("weather").with_attribute("temperature", AttributeValue::Float(85.0));

        // Match the events against subscriptions
        let matches1 = matcher.match_event(&high_temp_event).unwrap();
        let matches2 = matcher.match_event(&low_temp_event).unwrap();

        // Check if our subscription matched correctly
        assert!(matches1.contains("high-temp-alert"));
        assert!(!matches2.contains("high-temp-alert"));
    }

    #[test]
    fn test_multiple_subscriptions() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create subscriptions
        let sub1 = Subscription::new("sub1").with_predicate(ElementaryPredicate::new(
            ElementaryTest::Equals {
                attribute: "topic".to_string(),
                value: AttributeValue::String("news".to_string()),
            },
            false,
        ));

        let sub2 = Subscription::new("sub2")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("news".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Contains {
                    attribute: "category".to_string(),
                    substring: "tech".to_string(),
                },
                false,
            ));

        // Add the subscriptions to the matcher
        matcher.add_subscription(sub1);
        matcher.add_subscription(sub2);

        // Create an event that matches both subscriptions
        let event = DefaultEvent::new("news")
            .with_attribute("category", AttributeValue::String("tech news".to_string()));

        // Match the event against subscriptions
        let matches = matcher.match_event(&event).unwrap();

        // Check if both subscriptions matched
        assert!(matches.contains("sub1"));
        assert!(matches.contains("sub2"));
        assert_eq!(matches.len(), 2);
    }

    #[test]
    fn test_subscription_removal() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a subscription
        let subscription = Subscription::new("test-sub").with_predicate(ElementaryPredicate::new(
            ElementaryTest::Equals {
                attribute: "topic".to_string(),
                value: AttributeValue::String("test".to_string()),
            },
            false,
        ));

        // Add the subscription to the matcher
        matcher.add_subscription(subscription);

        // Create an event
        let event = DefaultEvent::new("test");

        // Match the event against subscriptions
        let matches1 = matcher.match_event(&event).unwrap();
        assert!(matches1.contains("test-sub"));

        // Remove the subscription
        matcher.remove_subscription(&"test-sub").unwrap();

        // Match the event again
        let matches2 = matcher.match_event(&event).unwrap();
        assert!(!matches2.contains("test-sub"));
        assert_eq!(matches2.len(), 0);
    }

    #[test]
    fn test_regex_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a subscription with a regex pattern
        let subscription = Subscription::new("regex-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::regex("topic".to_string(), "news|weather").unwrap(),
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::regex("category".to_string(), "^tech.*").unwrap(),
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(subscription);

        // Create matching events
        let matching_event1 = DefaultEvent::new("news")
            .with_attribute("category", AttributeValue::String("technology".to_string()));

        let matching_event2 = DefaultEvent::new("weather").with_attribute(
            "category",
            AttributeValue::String("tech-forecast".to_string()),
        );

        // Create non-matching events
        let non_matching_event1 = DefaultEvent::new("sports")
            .with_attribute("category", AttributeValue::String("technology".to_string()));

        let non_matching_event2 = DefaultEvent::new("news")
            .with_attribute("category", AttributeValue::String("politics".to_string()));

        // Match the events against subscriptions
        let matches1 = matcher.match_event(&matching_event1).unwrap();
        let matches2 = matcher.match_event(&matching_event2).unwrap();
        let matches3 = matcher.match_event(&non_matching_event1).unwrap();
        let matches4 = matcher.match_event(&non_matching_event2).unwrap();

        // Check if our subscription matched correctly
        assert!(matches1.contains("regex-test"));
        assert!(matches2.contains("regex-test"));
        assert!(!matches3.contains("regex-test"));
        assert!(!matches4.contains("regex-test"));
    }

    #[test]
    fn test_string_attribute_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create subscriptions for different string operations
        let equals_sub = Subscription::new("equals-test").with_predicate(ElementaryPredicate::new(
            ElementaryTest::Equals {
                attribute: "topic".to_string(),
                value: AttributeValue::String("news".to_string()),
            },
            false,
        ));

        let contains_sub =
            Subscription::new("contains-test").with_predicate(ElementaryPredicate::new(
                ElementaryTest::Contains {
                    attribute: "headline".to_string(),
                    substring: "breaking".to_string(),
                },
                false,
            ));

        let starts_with_sub =
            Subscription::new("starts-with-test").with_predicate(ElementaryPredicate::new(
                ElementaryTest::StartsWith {
                    attribute: "headline".to_string(),
                    prefix: "URGENT".to_string(),
                },
                false,
            ));

        let ends_with_sub =
            Subscription::new("ends-with-test").with_predicate(ElementaryPredicate::new(
                ElementaryTest::EndsWith {
                    attribute: "headline".to_string(),
                    suffix: "today".to_string(),
                },
                false,
            ));

        // Add the subscriptions to the matcher
        matcher.add_subscription(equals_sub);
        matcher.add_subscription(contains_sub);
        matcher.add_subscription(starts_with_sub);
        matcher.add_subscription(ends_with_sub);

        // Create an event that matches all string operations
        let event = DefaultEvent::new("news").with_attribute(
            "headline",
            AttributeValue::String("URGENT: breaking news today".to_string()),
        );

        // Match the event against subscriptions
        let matches = matcher.match_event(&event).unwrap();

        // Check if all subscriptions matched
        assert!(matches.contains("equals-test"));
        assert!(matches.contains("contains-test"));
        assert!(matches.contains("starts-with-test"));
        assert!(matches.contains("ends-with-test"));
    }

    #[test]
    fn test_numeric_attribute_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create subscriptions for different numeric operations
        let int_equals_sub = Subscription::new("int-equals-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("stats".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "count".to_string(),
                    value: AttributeValue::Integer(100),
                },
                false,
            ));

        let float_equals_sub = Subscription::new("float-equals-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("stats".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "percentage".to_string(),
                    value: AttributeValue::Float(75.5),
                },
                false,
            ));

        let greater_than_sub = Subscription::new("greater-than-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("stats".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::GreaterThan {
                    attribute: "count".to_string(),
                    value: 50.0,
                },
                false,
            ));

        let less_than_sub = Subscription::new("less-than-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("stats".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::LessThan {
                    attribute: "percentage".to_string(),
                    value: 80.0,
                },
                false,
            ));

        // Add the subscriptions to the matcher
        matcher.add_subscription(int_equals_sub);
        matcher.add_subscription(float_equals_sub);
        matcher.add_subscription(greater_than_sub);
        matcher.add_subscription(less_than_sub);

        // Create an event that matches all numeric operations
        let event = DefaultEvent::new("stats")
            .with_attribute("count", AttributeValue::Integer(100))
            .with_attribute("percentage", AttributeValue::Float(75.5));

        // Match the event against subscriptions
        let matches = matcher.match_event(&event).unwrap();

        // Check if all subscriptions matched
        assert!(matches.contains("int-equals-test"));
        assert!(matches.contains("float-equals-test"));
        assert!(matches.contains("greater-than-test"));
        assert!(matches.contains("less-than-test"));

        // Test integer comparison with float values
        let int_gt_sub = Subscription::new("int-gt-test").with_predicate(ElementaryPredicate::new(
            ElementaryTest::GreaterThan {
                attribute: "value".to_string(),
                value: 50.0,
            },
            false,
        ));

        let int_lt_sub = Subscription::new("int-lt-test").with_predicate(ElementaryPredicate::new(
            ElementaryTest::LessThan {
                attribute: "value".to_string(),
                value: 150.0,
            },
            false,
        ));

        let mut int_comparison_matcher = Matcher::new();
        int_comparison_matcher.add_subscription(int_gt_sub);
        int_comparison_matcher.add_subscription(int_lt_sub);

        let int_event = DefaultEvent::new("test")
            .with_attribute("value".to_string(), AttributeValue::Integer(100));

        let int_matches = int_comparison_matcher.match_event(&int_event).unwrap();
        assert!(int_matches.contains("int-gt-test"));
        assert!(int_matches.contains("int-lt-test"));
    }

    #[test]
    fn test_boolean_attribute_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create subscriptions for boolean attributes
        let true_sub = Subscription::new("true-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("status".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "active".to_string(),
                    value: AttributeValue::Boolean(true),
                },
                false,
            ));

        let false_sub = Subscription::new("false-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("status".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "completed".to_string(),
                    value: AttributeValue::Boolean(false),
                },
                false,
            ));

        // Add the subscriptions to the matcher
        matcher.add_subscription(true_sub);
        matcher.add_subscription(false_sub);

        // Create an event that matches both boolean subscriptions
        let event = DefaultEvent::new("status")
            .with_attribute("active", AttributeValue::Boolean(true))
            .with_attribute("completed", AttributeValue::Boolean(false));

        // Match the event against subscriptions
        let matches = matcher.match_event(&event).unwrap();

        // Check if both subscriptions matched
        assert!(matches.contains("true-test"));
        assert!(matches.contains("false-test"));
    }

    #[test]
    fn test_list_attribute_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a list of values
        let list = vec![
            AttributeValue::String("item1".to_string()),
            AttributeValue::String("item2".to_string()),
            AttributeValue::Integer(42),
        ];

        // Create a subscription for list equality
        let list_sub = Subscription::new("list-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("inventory".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "items".to_string(),
                    value: AttributeValue::List(list.clone()),
                },
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(list_sub);

        // Create an event with a matching list
        let event =
            DefaultEvent::new("inventory").with_attribute("items", AttributeValue::List(list));

        // Match the event against subscriptions
        let matches = matcher.match_event(&event).unwrap();

        // Check if the subscription matched
        assert!(matches.contains("list-test"));
    }

    #[test]
    fn test_map_attribute_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a map of values
        let mut map = AttributeMap::new();
        map.insert(
            "key1".to_string(),
            AttributeValue::String("value1".to_string()),
        );
        map.insert("key2".to_string(), AttributeValue::Integer(42));
        map.insert("key3".to_string(), AttributeValue::Boolean(true));

        // Create a subscription for map equality
        let map_sub = Subscription::new("map-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("config".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "settings".to_string(),
                    value: AttributeValue::Map(map.clone()),
                },
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(map_sub);

        // Create an event with a matching map
        let event =
            DefaultEvent::new("config").with_attribute("settings", AttributeValue::Map(map));

        // Match the event against subscriptions
        let matches = matcher.match_event(&event).unwrap();

        // Check if the subscription matched
        assert!(matches.contains("map-test"));
    }

    #[test]
    fn test_in_operator_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a list of values for the IN operator
        let values = vec![
            AttributeValue::String("apple".to_string()),
            AttributeValue::String("banana".to_string()),
            AttributeValue::String("cherry".to_string()),
        ];

        // Create a subscription using the IN operator
        let in_sub = Subscription::new("in-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("fruits".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::In {
                    attribute: "fruit".to_string(),
                    values: values.clone(),
                },
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(in_sub);

        // Create events with different fruit values
        let matching_event = DefaultEvent::new("fruits")
            .with_attribute("fruit", AttributeValue::String("banana".to_string()));

        let non_matching_event = DefaultEvent::new("fruits")
            .with_attribute("fruit", AttributeValue::String("orange".to_string()));

        // Match the events against subscriptions
        let matches1 = matcher.match_event(&matching_event).unwrap();
        let matches2 = matcher.match_event(&non_matching_event).unwrap();

        // Check if the subscription matched correctly
        assert!(matches1.contains("in-test"));
        assert!(!matches2.contains("in-test"));
    }

    #[test]
    fn test_exists_operator_matching() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a subscription using the EXISTS operator
        let exists_sub = Subscription::new("exists-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("user".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Exists {
                    attribute: "email".to_string(),
                },
                false,
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(exists_sub);

        // Create events with and without the email attribute
        let matching_event = DefaultEvent::new("user").with_attribute(
            "email",
            AttributeValue::String("user@example.com".to_string()),
        );

        let non_matching_event = DefaultEvent::new("user")
            .with_attribute("name", AttributeValue::String("John Doe".to_string()));

        // Match the events against subscriptions
        let matches1 = matcher.match_event(&matching_event).unwrap();
        let matches2 = matcher.match_event(&non_matching_event).unwrap();

        // Check if the subscription matched correctly
        assert!(matches1.contains("exists-test"));
        assert!(!matches2.contains("exists-test"));
    }

    #[test]
    fn test_negated_predicates() {
        // Create a matcher
        let mut matcher = Matcher::new();

        // Create a subscription with negated predicates
        let negated_sub = Subscription::new("negated-test")
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String("product".to_string()),
                },
                false,
            ))
            .with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "category".to_string(),
                    value: AttributeValue::String("electronics".to_string()),
                },
                true, // Negated
            ));

        // Add the subscription to the matcher
        matcher.add_subscription(negated_sub);

        // Create events with different categories
        let matching_event = DefaultEvent::new("product")
            .with_attribute("category", AttributeValue::String("clothing".to_string()));

        let non_matching_event = DefaultEvent::new("product").with_attribute(
            "category",
            AttributeValue::String("electronics".to_string()),
        );

        // Match the events against subscriptions
        let matches1 = matcher.match_event(&matching_event).unwrap();
        let matches2 = matcher.match_event(&non_matching_event).unwrap();

        // Check if the subscription matched correctly
        assert!(matches1.contains("negated-test"));
        assert!(!matches2.contains("negated-test"));
    }

    #[test]
    fn test_parameterized_topic_exact_match() {
        // Test that subscriptions to parameterized topics (with dynamic parameters) work correctly
        // This tests the new event format: "module::path::EventName::param1::param2"
        let mut matcher = Matcher::new();

        // Create subscriptions for specific rex reports with exact topic matching
        let rex_id_1 = "FKuVz1XP7YJKJq9rP2vzCBqfGxQ3GKJr9ZrH7X9K6ZQz";
        let rex_id_2 = "8Znk9wMC8YqfPNf4L3XzQ5rP7zK2vR9xP3YfQ8nK4ZQz";

        // Subscribe to rex 1 reports
        let rex_1_sub = Subscription::new("rex-1-sub").with_predicate(ElementaryPredicate::new(
            ElementaryTest::Equals {
                attribute: "topic".to_string(),
                value: AttributeValue::String(format!(
                    "rialo_rex_processor_interface::event::RexReportEvent::{}",
                    rex_id_1
                )),
            },
            false,
        ));

        // Subscribe to rex 2 reports
        let rex_2_sub = Subscription::new("rex-2-sub").with_predicate(ElementaryPredicate::new(
            ElementaryTest::Equals {
                attribute: "topic".to_string(),
                value: AttributeValue::String(format!(
                    "rialo_rex_processor_interface::event::RexReportEvent::{}",
                    rex_id_2
                )),
            },
            false,
        ));

        matcher.add_subscription(rex_1_sub);
        matcher.add_subscription(rex_2_sub);

        // Create events from different REX requests
        let rex_1_event = DefaultEvent::new(format!(
            "rialo_rex_processor_interface::event::RexReportEvent::{}",
            rex_id_1
        ))
        .with_attribute("data", AttributeValue::String("report data 1".to_string()));

        let rex_2_event = DefaultEvent::new(format!(
            "rialo_rex_processor_interface::event::RexReportEvent::{}",
            rex_id_2
        ))
        .with_attribute("data", AttributeValue::String("report data 2".to_string()));

        // Match the events
        let matches1 = matcher.match_event(&rex_1_event).unwrap();
        let matches2 = matcher.match_event(&rex_2_event).unwrap();

        // Each subscription should only match its specific rex
        assert!(matches1.contains("rex-1-sub"));
        assert!(!matches1.contains("rex-2-sub"));

        assert!(matches2.contains("rex-2-sub"));
        assert!(!matches2.contains("rex-1-sub"));
    }

    #[test]
    fn test_parameterized_topic_regex_match() {
        // Test that regex patterns can match parameterized topics
        let mut matcher = Matcher::new();

        // Create a subscription that matches ANY RexReportEvent regardless of rex_id
        let all_reports_sub =
            Subscription::new("all-reports-sub").with_predicate(ElementaryPredicate::new(
                ElementaryTest::regex(
                    "topic".to_string(),
                    "^rialo_rex_processor_interface::event::RexReportEvent::.*",
                )
                .unwrap(),
                false,
            ));

        // Create a subscription that matches a specific pattern in rex IDs
        let specific_pattern_sub =
            Subscription::new("specific-pattern-sub").with_predicate(ElementaryPredicate::new(
                ElementaryTest::regex("topic".to_string(), ".*::FKuVz.*").unwrap(),
                false,
            ));

        matcher.add_subscription(all_reports_sub);
        matcher.add_subscription(specific_pattern_sub);

        // Create events with different rex IDs
        let matching_event = DefaultEvent::new(
            "rialo_rex_processor_interface::event::RexReportEvent::FKuVz1XP7YJKJq9rP2vzCBqfGxQ3GKJr9ZrH7X9K6ZQz"
                .to_string(),
        )
        .with_attribute("data", AttributeValue::String("report".to_string()));

        let partial_match_event = DefaultEvent::new(
            "rialo_rex_processor_interface::event::RexReportEvent::8Znk9wMC8YqfPNf4L3XzQ5rP7zK2vR9xP3YfQ8nK4ZQz"
                .to_string(),
        )
        .with_attribute("data", AttributeValue::String("report".to_string()));

        // Match the events
        let matches1 = matcher.match_event(&matching_event).unwrap();
        let matches2 = matcher.match_event(&partial_match_event).unwrap();

        // First event matches both subscriptions
        assert!(matches1.contains("all-reports-sub"));
        assert!(matches1.contains("specific-pattern-sub"));

        // Second event only matches the general subscription
        assert!(matches2.contains("all-reports-sub"));
        assert!(!matches2.contains("specific-pattern-sub"));
    }

    #[test]
    fn test_parameterized_topic_special_characters() {
        // Test that base58-encoded pubkeys (which contain alphanumeric characters) work correctly
        let mut matcher = Matcher::new();

        // Base58 characters include: 1-9, A-Z, a-z (excluding 0, O, I, l to avoid confusion)
        let pubkey_with_special_chars = "11111111111111111111111111111111"; // All 1s - valid base58

        let subscription =
            Subscription::new("special-chars-sub").with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String(format!(
                        "rialo_rex_processor_interface::event::RexReportEvent::{}",
                        pubkey_with_special_chars
                    )),
                },
                false,
            ));

        matcher.add_subscription(subscription);

        let matching_event = DefaultEvent::new(format!(
            "rialo_rex_processor_interface::event::RexReportEvent::{}",
            pubkey_with_special_chars
        ));

        let matches = matcher.match_event(&matching_event).unwrap();
        assert!(matches.contains("special-chars-sub"));
    }

    #[test]
    fn test_parameterized_topic_case_sensitivity() {
        // Test that topic matching is case-sensitive
        let mut matcher = Matcher::new();

        let topic_lower =
            "rialo_rex_processor_interface::event::RexReportEvent::abc123".to_string();
        let topic_upper =
            "rialo_rex_processor_interface::event::RexReportEvent::ABC123".to_string();

        // Subscribe to lowercase version
        let lowercase_sub =
            Subscription::new("lowercase-sub").with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String(topic_lower.clone()),
                },
                false,
            ));

        matcher.add_subscription(lowercase_sub);

        // Create events with different cases
        let lowercase_event = DefaultEvent::new(topic_lower);
        let uppercase_event = DefaultEvent::new(topic_upper);

        let matches_lower = matcher.match_event(&lowercase_event).unwrap();
        let matches_upper = matcher.match_event(&uppercase_event).unwrap();

        // Only the lowercase event should match
        assert!(matches_lower.contains("lowercase-sub"));
        assert!(!matches_upper.contains("lowercase-sub"));
    }

    #[test]
    fn test_parameterized_topic_multiple_parameters() {
        // Test topics with multiple parameters separated by `::`
        // Format: "EventName::param1::param2::param3"
        let mut matcher = Matcher::new();

        let multi_param_topic = "rialo_custom_interface::event::MultiParamEvent::1::FKuVz1XP7YJKJq9rP2vzCBqfGxQ3GKJr9ZrH7X9K6ZQz::active".to_string();

        // Exact match subscription
        let exact_sub =
            Subscription::new("exact-multi-sub").with_predicate(ElementaryPredicate::new(
                ElementaryTest::Equals {
                    attribute: "topic".to_string(),
                    value: AttributeValue::String(multi_param_topic.clone()),
                },
                false,
            ));

        // Regex subscription matching any MultiParamEvent with param1=1
        let regex_sub =
            Subscription::new("regex-multi-sub").with_predicate(ElementaryPredicate::new(
                ElementaryTest::regex(
                    "topic".to_string(),
                    "^rialo_custom_interface::event::MultiParamEvent::1::.*",
                )
                .unwrap(),
                false,
            ));

        matcher.add_subscription(exact_sub);
        matcher.add_subscription(regex_sub);

        let matching_event = DefaultEvent::new(multi_param_topic);
        let partial_event = DefaultEvent::new(
            "rialo_custom_interface::event::MultiParamEvent::1::8Znk9wMC8YqfPNf4L3XzQ5rP7zK2vR9xP3YfQ8nK4ZQz::inactive".to_string()
        );
        let non_matching_event = DefaultEvent::new(
            "rialo_custom_interface::event::MultiParamEvent::2::FKuVz1XP7YJKJq9rP2vzCBqfGxQ3GKJr9ZrH7X9K6ZQz::active".to_string()
        );

        let matches1 = matcher.match_event(&matching_event).unwrap();
        let matches2 = matcher.match_event(&partial_event).unwrap();
        let matches3 = matcher.match_event(&non_matching_event).unwrap();

        // First event matches both
        assert!(matches1.contains("exact-multi-sub"));
        assert!(matches1.contains("regex-multi-sub"));

        // Second event only matches regex (param1=1 but different other params)
        assert!(!matches2.contains("exact-multi-sub"));
        assert!(matches2.contains("regex-multi-sub"));

        // Third event matches neither (param1=2)
        assert!(!matches3.contains("exact-multi-sub"));
        assert!(!matches3.contains("regex-multi-sub"));
    }
}
