# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

import os
import shutil
import tempfile

from botocore.compat import OrderedDict

from awscli.customizations.eks.kubeconfig import (
    Kubeconfig,
    KubeconfigInaccessableError,
    KubeconfigLoader,
    KubeconfigValidator,
    KubeconfigWriter,
    _get_new_kubeconfig_content,
)
from awscli.testutils import mock, unittest
from tests.functional.eks.test_util import get_testdata


class TestKubeconfigWriter(unittest.TestCase):
    def setUp(self):
        self._writer = KubeconfigWriter()

    def test_write_order(self):
        content = OrderedDict(
            [("current-context", "context"), ("apiVersion", "v1")]
        )
        file_to_write = tempfile.NamedTemporaryFile(mode='w').name
        self.addCleanup(os.remove, file_to_write)

        config = Kubeconfig(file_to_write, content)
        self._writer.write_kubeconfig(config)

        with open(file_to_write) as stream:
            self.assertMultiLineEqual(
                stream.read(), "current-context: context\n" "apiVersion: v1\n"
            )

    def test_write_makedirs(self):
        content = OrderedDict(
            [("current-context", "context"), ("apiVersion", "v1")]
        )
        containing_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, containing_dir)
        config_path = os.path.join(containing_dir, "dir1", "dir2", "dir3")

        config = Kubeconfig(config_path, content)
        self._writer.write_kubeconfig(config)

        with open(config_path) as stream:
            self.assertMultiLineEqual(
                stream.read(), "current-context: context\n" "apiVersion: v1\n"
            )

    def test_write_directory(self):
        content = OrderedDict(
            [("current-context", "context"), ("apiVersion", "v1")]
        )
        containing_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, containing_dir)

        config = Kubeconfig(containing_dir, content)
        self.assertRaises(
            KubeconfigInaccessableError, self._writer.write_kubeconfig, config
        )


class TestKubeconfigLoader(unittest.TestCase):
    def setUp(self):
        # This mock validator allows all kubeconfigs
        self._validator = mock.Mock(spec=KubeconfigValidator)
        self._loader = KubeconfigLoader(self._validator)

        self._temp_directory = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self._temp_directory)

    def _clone_config(self, config):
        """
        Copies the testdata named config into the temp directory,
        Returns the new path

        :param config: The name of the testdata to copy
        :type config: str
        """
        old_path = os.path.abspath(get_testdata(config))
        new_path = os.path.join(self._temp_directory, config)
        shutil.copy2(old_path, new_path)
        return new_path

    def test_load_simple(self):
        simple_path = self._clone_config("valid_simple")
        content = OrderedDict(
            [
                ("apiVersion", "v1"),
                (
                    "clusters",
                    [
                        OrderedDict(
                            [
                                (
                                    "cluster",
                                    OrderedDict([("server", "simple")]),
                                ),
                                ("name", "simple"),
                            ]
                        )
                    ],
                ),
                ("contexts", None),
                ("current-context", "simple"),
                ("kind", "Config"),
                ("preferences", OrderedDict()),
                ("users", None),
            ]
        )
        loaded_config = self._loader.load_kubeconfig(simple_path)
        self.assertEqual(loaded_config.content, content)
        self._validator.validate_config.assert_called_with(
            Kubeconfig(simple_path, content)
        )

    def test_load_noexist(self):
        no_exist_path = os.path.join(
            self._temp_directory, "this_does_not_exist"
        )
        loaded_config = self._loader.load_kubeconfig(no_exist_path)
        self.assertEqual(loaded_config.content, _get_new_kubeconfig_content())
        self._validator.validate_config.assert_called_with(
            Kubeconfig(no_exist_path, _get_new_kubeconfig_content())
        )

    def test_load_empty(self):
        empty_path = self._clone_config("valid_empty_existing")
        loaded_config = self._loader.load_kubeconfig(empty_path)
        self.assertEqual(loaded_config.content, _get_new_kubeconfig_content())
        self._validator.validate_config.assert_called_with(
            Kubeconfig(empty_path, _get_new_kubeconfig_content())
        )

    def test_load_directory(self):
        current_directory = self._temp_directory
        self.assertRaises(
            KubeconfigInaccessableError,
            self._loader.load_kubeconfig,
            current_directory,
        )
        self._validator.validate_config.assert_not_called()
