"""Provide Filter class."""

import re
from ast import literal_eval
from typing import List, Optional, Pattern

from .parserevent import ParserEvent


class Filter:
    """Filter class.

    The Filter class is used to filter events according to the exclude and
    include rules.
    """

    def __init__(self, exclude: str, include: str):
        """Construct Filter class.

        :param exclude: The exclude rules
        :type exclude: str
        :param include: The include rules
        :type include: str
        """
        self._exclude = Filter.set_rules(exclude)
        self._include = Filter.set_rules(include)

    @staticmethod
    def set_rules(rules: str) -> List[Pattern]:
        """Set the given rules into an array which is returned.

        :param rules: The rules to set
        :type rules: str
        :return: An array of regular expressions
        :rtype: List[Pattern]
        """
        arr = []
        if rules != "":
            for rule in literal_eval(rules):
                if rule.startswith("/"):
                    re_flags = re.NOFLAG
                    [expr, flags] = rule[1:].split("/")
                    for flag in flags:
                        match flag:
                            case "i":
                                re_flags |= re.IGNORECASE
                            case "m":
                                re_flags |= re.MULTILINE
                            case "s":
                                re_flags |= re.DOTALL
                    arr.append(re.compile(expr, re_flags))
                else:
                    arr.append(re.compile(rule, re.IGNORECASE))
        return arr

    def _is_match(
        self, summary: str, description: Optional[str], regexes: List[Pattern]
    ) -> bool:
        """Indicate if the event matches the given list of regular expressions.

        :param summary: The event summary to examine
        :type summary: str
        :param description: The event description summary to examine
        :type description: Optional[str]
        :param regexes: The regular expressions to match against
        :type regexes: List[]
        :return: True if the event matches the exclude filter
        :rtype: bool
        """
        for regex in regexes:
            if regex.search(summary) or (
                description and regex.search(description)
            ):
                return True

        return False

    def _is_excluded(self, summary: str, description: Optional[str]) -> bool:
        """Indicate if the event should be excluded.

        :param summary: The event summary to examine
        :type summary: str
        :param description: The event description summary to examine
        :type description: Optional[str]
        :return: True if the event matches the exclude filter
        :rtype: bool
        """
        return self._is_match(summary, description, self._exclude)

    def _is_included(self, summary: str, description: Optional[str]) -> bool:
        """Indicate if the event should be included.

        :param summary: The event summary to examine
        :type summary: str
        :param description: The event description summary to examine
        :type description: Optional[str]
        :return: True if the event matches the include filter
        :rtype: bool
        """
        return self._is_match(summary, description, self._include)

    def filter(self, summary: str, description: Optional[str]) -> bool:
        """Check if the event should be included or not.

        :param summary: The event summary to examine
        :type summary: str
        :param description: The event description summary to examine
        :type description: Optional[str]
        :return: true if the event should be included, otherwise false
        :rtype: bool
        """
        add_event = not self._is_excluded(summary, description)
        if not add_event:
            add_event = self._is_included(summary, description)
        return add_event

    def filter_event(self, event: ParserEvent) -> bool:
        """Check if the event should be included or not.

        :param event: The event to examine
        :type event: ParserEvent
        :return: true if the event should be included, otherwise false
        :rtype: bool
        """
        return self.filter(event.summary, event.description)
