from unittest import TestCase, mock
from click.testing import CliRunner
from kfk.commands.clusters import kfk
from kfk.kubectl_command_builder import Kubectl


class TestKfkClusters(TestCase):

    def setUp(self):
        self.runner = CliRunner()
        self.cluster = "my-cluster"
        self.namespace = "kafka"
        self.new_cluster_name = "my-cluster-with-new-name"

    def test_no_option(self):
        result = self.runner.invoke(kfk, ['clusters', '--cluster', self.cluster, '-n', self.namespace])
        assert result.exit_code == 0
        assert "Missing options: kfk clusters" in result.output

    @mock.patch('kfk.commands.clusters.os')
    def test_list_clusters(self, mock_os):
        result = self.runner.invoke(kfk, ['clusters', '--list', '-n', self.namespace])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(Kubectl().get().kafkas().namespace(self.namespace).build())

    @mock.patch('kfk.commands.clusters.os')
    def test_list_clusters_all_namespaces(self, mock_os):
        result = self.runner.invoke(kfk, ['clusters', '--list'])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(Kubectl().get().kafkas().namespace().build())

    @mock.patch('kfk.commands.clusters.os')
    def test_describe_cluster(self, mock_os):
        result = self.runner.invoke(kfk, ['clusters', '--describe', '--cluster', self.cluster, '-n', self.namespace])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(Kubectl().describe().kafkas(self.cluster).namespace(self.namespace).build())

    @mock.patch('kfk.commands.clusters.os')
    def test_describe_cluster_output_yaml(self, mock_os):
        result = self.runner.invoke(kfk,
                                    ['clusters', '--describe', '--cluster', self.cluster, '-n', self.namespace, '-o',
                                     'yaml'])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(
            Kubectl().get().kafkas(self.cluster).namespace(self.namespace).output("yaml").build())

    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_without_parameters(self, mock_os):
        result = self.runner.invoke(kfk, ['clusters', '--alter', '--cluster', self.cluster, '-n', self.namespace])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(Kubectl().edit().kafkas(self.cluster).namespace(self.namespace).build())

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_one_additional_config(self, mock_os, mock_get_resource_yaml, mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--config', 'unclean.leader.election.enable=true',
                                              '--cluster', self.cluster, '-n', self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_with_one_additional_config.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_two_additional_configs(self, mock_os, mock_get_resource_yaml, mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--config', 'unclean.leader.election.enable=true',
                                              '--config', 'log.retention.hours=168',
                                              '--cluster', self.cluster, '-n', self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_with_two_additional_configs.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_two_additional_configs_delete_one_config(self, mock_os, mock_get_resource_yaml,
                                                                         mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral_with_two_additional_configs.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--delete-config', 'log.retention.hours',
                                              '--cluster', self.cluster, '-n', self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_with_one_additional_config.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_two_additional_configs_delete_two_configs(self, mock_os, mock_get_resource_yaml,
                                                                          mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral_with_two_additional_configs.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--delete-config', 'log.retention.hours',
                                              '--delete-config', 'unclean.leader.election.enable', '--cluster',
                                              self.cluster, '-n', self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_two_additional_configs_deleted.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_one_replica(self, mock_os, mock_get_resource_yaml, mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral_name_updated.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--replicas', 1, '--cluster', self.cluster, '-n',
                                              self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_with_one_replica.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_two_replicas(self, mock_os, mock_get_resource_yaml, mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral_name_updated.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--replicas', 2, '--cluster', self.cluster, '-n',
                                              self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_with_two_replicas.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commons.get_resource_yaml')
    @mock.patch('kfk.commands.clusters.os')
    def test_alter_cluster_with_one_replica_one_zk_replica(self, mock_os, mock_get_resource_yaml,
                                                           mock_create_temp_file):
        with open(r'files/yaml/kafka-ephemeral_name_updated.yaml') as file:
            kafka_yaml = file.read()
            mock_get_resource_yaml.return_value = kafka_yaml
            result = self.runner.invoke(kfk, ['clusters', '--alter', '--replicas', 1, '--zk-replicas', 1, '--cluster',
                                              self.cluster, '-n', self.namespace])
            assert result.exit_code == 0

            with open(r'files/yaml/kafka-ephemeral_with_one_replica_one_zk_replica.yaml') as file:
                expected_kafka_yaml = file.read()
                result_kafka_yaml = mock_create_temp_file.call_args[0][0]
                assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_delete_cluster(self, mock_os, mock_click_confirm):
        mock_click_confirm.return_value = True
        result = self.runner.invoke(kfk, ['clusters', '--delete', '--cluster', self.cluster, '-n', self.namespace])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(Kubectl().delete().kafkas(self.cluster).namespace(self.namespace).build())

    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_delete_cluster_with_yes_flag(self, mock_os, mock_click_confirm):
        mock_click_confirm.return_value = False
        result = self.runner.invoke(kfk,
                                    ['clusters', '--delete', '--cluster', self.cluster, '-n', self.namespace, '-y'])
        assert result.exit_code == 0
        mock_os.system.assert_called_with(Kubectl().delete().kafkas(self.cluster).namespace(self.namespace).build())

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commands.clusters.open_file_in_system_editor')
    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_create_cluster(self, mock_os, mock_click_confirm, mock_open_file_in_system_editor, mock_create_temp_file):
        mock_click_confirm.return_value = True

        result = self.runner.invoke(kfk,
                                    ['clusters', '--create', '--cluster', self.new_cluster_name, '-n', self.namespace])
        assert result.exit_code == 0

        with open(r'files/yaml/kafka-ephemeral_name_updated.yaml') as file:
            expected_kafka_yaml = file.read()
            result_kafka_yaml = mock_create_temp_file.call_args[0][0]
            assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commands.clusters.open_file_in_system_editor')
    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_create_cluster_with_yes_flag(self, mock_os, mock_click_confirm, mock_open_file_in_system_editor,
                                          mock_create_temp_file):
        mock_click_confirm.return_value = False

        result = self.runner.invoke(kfk,
                                    ['clusters', '--create', '--cluster', self.new_cluster_name, '-n', self.namespace,
                                     '-y'])
        assert result.exit_code == 0

        mock_open_file_in_system_editor.assert_not_called()
        with open(r'files/yaml/kafka-ephemeral_name_updated.yaml') as file:
            expected_kafka_yaml = file.read()
            result_kafka_yaml = mock_create_temp_file.call_args[0][0]
            assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commands.clusters.open_file_in_system_editor')
    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_create_cluster_with_one_replica(self, mock_os, mock_click_confirm, mock_open_file_in_system_editor,
                                             mock_create_temp_file):
        mock_click_confirm.return_value = True

        result = self.runner.invoke(kfk,
                                    ['clusters', '--create', '--cluster', self.new_cluster_name, '--replicas', 1, '-n',
                                     self.namespace])
        assert result.exit_code == 0

        with open(r'files/yaml/kafka-ephemeral_with_one_replica.yaml') as file:
            expected_kafka_yaml = file.read()
            result_kafka_yaml = mock_create_temp_file.call_args[0][0]
            assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commands.clusters.open_file_in_system_editor')
    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_create_cluster_with_two_replicas(self, mock_os, mock_click_confirm, mock_open_file_in_system_editor,
                                              mock_create_temp_file):
        mock_click_confirm.return_value = True

        result = self.runner.invoke(kfk,
                                    ['clusters', '--create', '--cluster', self.new_cluster_name, '--replicas', 2, '-n',
                                     self.namespace])
        assert result.exit_code == 0

        with open(r'files/yaml/kafka-ephemeral_with_two_replicas.yaml') as file:
            expected_kafka_yaml = file.read()
            result_kafka_yaml = mock_create_temp_file.call_args[0][0]
            assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commands.clusters.open_file_in_system_editor')
    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_create_cluster_with_three_replicas(self, mock_os, mock_click_confirm, mock_open_file_in_system_editor,
                                                mock_create_temp_file):
        mock_click_confirm.return_value = True

        result = self.runner.invoke(kfk,
                                    ['clusters', '--create', '--cluster', self.new_cluster_name, '--replicas', 3, '-n',
                                     self.namespace])
        assert result.exit_code == 0

        with open(r'files/yaml/kafka-ephemeral_name_updated.yaml') as file:
            expected_kafka_yaml = file.read()
            result_kafka_yaml = mock_create_temp_file.call_args[0][0]
            assert expected_kafka_yaml == result_kafka_yaml

    @mock.patch('kfk.commands.clusters.create_temp_file')
    @mock.patch('kfk.commands.clusters.open_file_in_system_editor')
    @mock.patch('kfk.commands.clusters.click.confirm')
    @mock.patch('kfk.commands.clusters.os')
    def test_create_cluster_with_one_replica_one_zk_replica(self, mock_os, mock_click_confirm,
                                                            mock_open_file_in_system_editor,
                                                            mock_create_temp_file):
        mock_click_confirm.return_value = True

        result = self.runner.invoke(kfk,
                                    ['clusters', '--create', '--cluster', self.new_cluster_name, '--replicas', 1,
                                     '--zk-replicas', 1, '-n', self.namespace])
        assert result.exit_code == 0

        with open(r'files/yaml/kafka-ephemeral_with_one_replica_one_zk_replica.yaml') as file:
            expected_kafka_yaml = file.read()
            result_kafka_yaml = mock_create_temp_file.call_args[0][0]
            assert expected_kafka_yaml == result_kafka_yaml
