import json
import unittest

import cfnlint
from taskcat._cfn.stack_url_helper import StackURLHelper


class TestStackURLHelper(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    @staticmethod
    def _load_template(template_path):
        try:
            cfn = cfnlint.decode.cfn_yaml.load(template_path)
        except Exception:
            # print("Exception parsing: '{}'".format(template_path))
            exit(1)
        return cfn

    # Test TemplateURL to path extraction
    def METHOD_NAME(self):
        with open("tests/data/stackurlhelper/test.json") as test_file:
            self.testers = json.load(test_file)
            self.testers = self.testers["tests"]

        total = len(self.testers)
        matched = 0

        for test in self.testers:
            helper = StackURLHelper()
            cfn = self._load_template(test["input"]["master_template"])
            helper.mappings = cfn.get("Mappings")
            helper.template_parameters = cfn.get("Parameters")

            # Setup default parameters
            default_parameters = {}
            for parameter in helper.template_parameters:
                properties = helper.template_parameters.get(parameter)
                if "Default" in properties.keys():
                    default_parameters[parameter] = properties["Default"]

            helper.SUBSTITUTION.update(default_parameters)

            test["input"]["parameter_values"] = {}

            # Inject Parameter Values
            if "parameter_values" in test["input"]:
                parameter_values = test["input"]["parameter_values"]
                helper.SUBSTITUTION.update(parameter_values)

            # print(test)
            # print(test["output"]["url_paths"])
            # print(helper.flatten_template_url(test["input"]["child_template"]))
            if test["output"]["url_paths"] == helper.flatten_template_url(
                test["input"]["child_template"],
            ):

                matched = matched + 1
        # print("matched {} total {}".format(matched, total))
        self.assertEqual(matched, total)

    def test_flatten_template_url_exceptions_split(self):
        helper = StackURLHelper()
        with self.assertRaises(Exception) as context:
            helper.flatten_template_url("{'Fn::Split'}")

        self.assertTrue("Fn::Split: not supported" in str(context.exception))

    def test_flatten_template_url_exceptions_getatt(self):
        helper = StackURLHelper()
        with self.assertRaises(Exception) as context:
            helper.flatten_template_url("{'Fn::GetAtt'}")

        self.assertTrue("Fn::GetAtt: not supported" in str(context.exception))

    def test_flatten_template_url_maxdepth(self):
        helper = StackURLHelper()
        with self.assertRaises(Exception) as context:
            helper.flatten_template_url(
                "{1{2{3{4{5{6{7{8{9{{{{{{{{{{{{21}}}}}}}}}}}}}}}}}}}}}"
            )

        self.assertTrue("Template URL contains more than" in str(context.exception))

    # Test TemplateURL to path extraction
    def test_find_local_child_template(self):
        with open("tests/data/stackurlhelper/test.json") as test_file:
            self.tests = json.load(test_file)
            self.tests = self.tests["tests"]

        total = 0
        matched = 0
        helper = StackURLHelper()
        for test in self.tests:
            index = 0
            for url_path in test["output"]["url_paths"]:
                total = total + 1
                master_template = test["input"]["master_template"]
                result = helper.find_local_child_template(master_template, url_path)
                expected = test["output"]["local_paths"][index]
                if str(result) == str(expected):
                    matched = matched + 1
                index = index + 1

        # print("matched {} total {}".format(matched, total))
        self.assertEqual(matched, total)

    def test_fn_findinmap_lookup(self):
        l_mappings = {
            "ami_lookup": {
                "us-east-1": {"ami": "this_one", "ami2": "that_one"},
                "us-east-2": {"ami": "is_this_one", "ami2": "is_that_one"},
                "us-west-1": {"ami": "not_this_one", "ami2": "not_that_one"},
            }
        }

        helper = StackURLHelper()
        helper.mappings = l_mappings

        mappings_map = "ami_lookup"
        first_key = "us-west-1"
        final_key = "ami2"

        result = helper.find_in_map_lookup(mappings_map, first_key, final_key)

        self.assertEqual(result, "not_that_one")

    # TODO: Test all the individual functions
    # TODO: Test fn_sub logic
    # def test_fn_sub(self):
    #     self.assertEqual(True, False)

    # TODO: Test local path Discovery
    # def test_fn_if(self):
    #     self.assertEqual(True, False)