"""
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""

import logging
from typing import List, Optional, Sequence, Union

from cfnlint.rules import Match, RulesCollection
from cfnlint.template import Template

LOGGER = logging.getLogger(__name__)


class Runner:
    """Run all the rules"""

    def __init__(
        self,
        rules: RulesCollection,
        filename: Optional[str],
        template: str,
        regions: Sequence[str],
        verbosity=0,
        mandatory_rules: Union[Sequence[str], None] = None,
    ):
        self.rules = rules
        self.filename = filename
        self.verbosity = verbosity
        self.mandatory_rules = mandatory_rules or []
        self.cfn = Template(filename, template, regions)

    def transform(self):
        """Transform logic"""
        matches = self.cfn.transform()
        return matches

    def run(self) -> List[Match]:
        """Run rules"""
        LOGGER.info("Run scan of template %s", self.filename)
        matches = []
        if self.cfn.template is not None:
            matches.extend(self.rules.run(self.filename, self.cfn))
        return self.check_metadata_directives(matches)

    def check_metadata_directives(self, matches: Sequence[Match]) -> List[Match]:
        # uniq the list of incidents and filter out exceptions from the template
        directives = self.cfn.get_directives()
        return_matches: List[Match] = []
        for match in matches:
            if not any(match == u for u in return_matches):
                if match.rule.id not in directives:
                    return_matches.append(match)
                else:
                    for mandatory_rule in self.mandatory_rules:
                        if match.rule.id.startswith(mandatory_rule):
                            return_matches.append(match)
                            break
                    else:
                        path = getattr(match, "path", None)
                        if path:
                            if len(path) >= 2:
                                if path[0] != "Resources":
                                    return_matches.append(match)
                                    continue
                                if path[1] not in directives[match.rule.id]:
                                    return_matches.append(match)
                            else:
                                return_matches.append(match)

        return return_matches
