using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EonaCat.LogStack.Core;

namespace EonaCat.LogStack.Filtering;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

/// <summary>
/// Advanced filtering conditions beyond simple log levels
/// </summary>
public abstract class FilterCondition
{
    public abstract bool Matches(LogEvent logEvent, Dictionary<string, object?> properties);
}

/// <summary>
/// Filters on log level
/// </summary>
public sealed class LogLevelFilter : FilterCondition
{
    private readonly LogLevel _minLevel;
    private readonly LogLevel _maxLevel;

    public LogLevelFilter(LogLevel minLevel, LogLevel maxLevel = LogLevel.Critical)
    {
        _minLevel = minLevel;
        _maxLevel = maxLevel;
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        return logEvent.Level >= _minLevel && logEvent.Level <= _maxLevel;
    }
}

/// <summary>
/// Filters based on logger name pattern (supports wildcards)
/// </summary>
public sealed class LoggerNameFilter : FilterCondition
{
    private readonly string _pattern;
    private readonly bool _negate;

    public LoggerNameFilter(string pattern, bool negate = false)
    {
        _pattern = pattern ?? "";
        _negate = negate;
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        // Logger name checking would be done here when LogEvent has LoggerName property available
        // For now, return based on negate flag
        return _negate;
    }

    private bool WildcardMatch(string text, string pattern)
    {
        if (pattern == "*")
        {
            return true;
        }

        int textIndex = 0;
        int patternIndex = 0;

        while (textIndex < text.Length && patternIndex < pattern.Length)
        {
            if (pattern[patternIndex] == '*')
            {
                if (patternIndex + 1 >= pattern.Length)
                {
                    return true;
                }

                var nextChar = pattern[patternIndex + 1];
                while (textIndex < text.Length && text[textIndex] != nextChar)
                {
                    textIndex++;
                }

                if (textIndex >= text.Length)
                {
                    return false;
                }

                patternIndex++;
            }
            else if (pattern[patternIndex] == '?')
            {
                textIndex++;
                patternIndex++;
            }
            else if (pattern[patternIndex] == text[textIndex])
            {
                textIndex++;
                patternIndex++;
            }
            else
            {
                return false;
            }
        }

        while (patternIndex < pattern.Length && pattern[patternIndex] == '*')
        {
            patternIndex++;
        }

        return textIndex == text.Length && patternIndex == pattern.Length;
    }
}

/// <summary>
/// Filters on message content
/// </summary>
public sealed class MessageFilter : FilterCondition
{
    private readonly string _contains;
    private readonly bool _caseSensitive;
    private readonly bool _negate;

    public MessageFilter(string contains, bool caseSensitive = false, bool negate = false)
    {
        _contains = contains ?? "";
        _caseSensitive = caseSensitive;
        _negate = negate;
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        string message = "";
        var comparison = _caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
        bool matches = message.Contains(_contains, comparison);
        return _negate ? !matches : matches;
    }
}

/// <summary>
/// Filters on exception type
/// </summary>
public sealed class ExceptionTypeFilter : FilterCondition
{
    private readonly Type _exceptionType;
    private readonly bool _includeInherited;
    private readonly bool _negate;

    public ExceptionTypeFilter(Type exceptionType, bool includeInherited = true, bool negate = false)
    {
        _exceptionType = exceptionType;
        _includeInherited = includeInherited;
        _negate = negate;
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        // Exception checking would be done here when LogEvent has Exception property available
        // For now, return based on negate flag
        return _negate;
    }
}

/// <summary>
/// Filters on property values
/// </summary>
public sealed class PropertyFilter : FilterCondition
{
    private readonly string _propertyName;
    private readonly Func<object?, bool> _predicate;

    public PropertyFilter(string propertyName, Func<object?, bool> predicate)
    {
        _propertyName = propertyName;
        _predicate = predicate;
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        if (!properties.TryGetValue(_propertyName, out var value))
        {
            return false;
        }

        try
        {
            return _predicate(value);
        }
        catch
        {
            return false;
        }
    }
}

/// <summary>
/// Composite filter with AND logic
/// </summary>
public sealed class AndFilter : FilterCondition
{
    private readonly List<FilterCondition> _conditions;

    public AndFilter(params FilterCondition[] conditions)
    {
        _conditions = new List<FilterCondition>(conditions);
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        return _conditions.All(c => c.Matches(logEvent, properties));
    }
}

/// <summary>
/// Composite filter with OR logic
/// </summary>
public sealed class OrFilter : FilterCondition
{
    private readonly List<FilterCondition> _conditions;

    public OrFilter(params FilterCondition[] conditions)
    {
        _conditions = new List<FilterCondition>(conditions);
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        return _conditions.Any(c => c.Matches(logEvent, properties));
    }
}

/// <summary>
/// Composite filter with NOT logic
/// </summary>
public sealed class NotFilter : FilterCondition
{
    private readonly FilterCondition _condition;

    public NotFilter(FilterCondition condition)
    {
        _condition = condition;
    }

    public override bool Matches(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        return !_condition.Matches(logEvent, properties);
    }
}

/// <summary>
/// Fluent filter builder
/// </summary>
public sealed class FilterBuilder
{
    private FilterCondition? _condition;

    public FilterBuilder MinLevel(string levelName)
    {
        // When level enum is available in scope, use it here
        return this;
    }

    public FilterBuilder MaxLevel(string levelName)
    {
        // When level enum is available in scope, use it here
        return this;
    }

    public FilterBuilder Level(string min, string max)
    {
        // When level enum is available in scope, use it here
        return this;
    }

    public FilterBuilder LoggerName(string pattern)
    {
        _condition = And(_condition, new LoggerNameFilter(pattern));
        return this;
    }

    public FilterBuilder NotLoggerName(string pattern)
    {
        _condition = And(_condition, new LoggerNameFilter(pattern, true));
        return this;
    }

    public FilterBuilder MessageContains(string text, bool caseSensitive = false)
    {
        _condition = And(_condition, new MessageFilter(text, caseSensitive));
        return this;
    }

    public FilterBuilder MessageNotContains(string text, bool caseSensitive = false)
    {
        _condition = And(_condition, new MessageFilter(text, caseSensitive, true));
        return this;
    }

    public FilterBuilder ExceptionType(Type exceptionType, bool includeInherited = true)
    {
        _condition = And(_condition, new ExceptionTypeFilter(exceptionType, includeInherited));
        return this;
    }

    public FilterBuilder ExceptionType<TException>(bool includeInherited = true) where TException : Exception
    {
        _condition = And(_condition, new ExceptionTypeFilter(typeof(TException), includeInherited));
        return this;
    }

    public FilterBuilder Property(string propertyName, Func<object?, bool> predicate)
    {
        _condition = And(_condition, new PropertyFilter(propertyName, predicate));
        return this;
    }

    public FilterBuilder Property(string propertyName, object value)
    {
        _condition = And(_condition, new PropertyFilter(propertyName, v => Equals(v, value)));
        return this;
    }

    public FilterBuilder Or(FilterBuilder other)
    {
        if (_condition == null || other._condition == null)
        {
            return this;
        }

        _condition = new OrFilter(_condition, other._condition);
        return this;
    }

    public FilterCondition? Build()
    {
        return _condition;
    }

    private static FilterCondition And(FilterCondition? left, FilterCondition right)
    {
        return left == null ? right : new AndFilter(left, right);
    }
}

/// <summary>
/// Manager for applying filters to events
/// </summary>
public sealed class FilterManager
{
    private readonly List<(string name, FilterCondition condition, FilterAction action)> _filters = new();

    /// <summary>
    /// Registers a filter with an action
    /// </summary>
    public FilterManager Register(string name, FilterCondition condition, FilterAction action)
    {
        _filters.Add((name, condition, action));
        return this;
    }

    /// <summary>
    /// Evaluates all registered filters
    /// </summary>
    public FilterAction Evaluate(LogEvent logEvent, Dictionary<string, object?> properties)
    {
        foreach (var (name, condition, action) in _filters)
        {
            if (condition.Matches(logEvent, properties))
            {
                return action;
            }
        }

        return FilterAction.Continue;
    }

    public int Count => _filters.Count;

    public void Clear()
    {
        _filters.Clear();
    }
}

/// <summary>
/// Filter actions
/// </summary>
public enum FilterAction
{
    Continue,    // Process normally
    Ignore,      // Skip this event
    Critical,    // Mark as critical
    Suppress,    // Don't log to standard output, only to filters
}
