import json
import sys
from contextlib import ExitStack

from ..test_managercli import TestCliCommand
from subscription_manager import syspurposelib
from subscription_manager import managercli

from ..fixture import Capture

from unittest.mock import patch


class TestAddonsCommand(TestCliCommand):
    command_class = managercli.AddonsCommand

    def _set_syspurpose(self, syspurpose):
        """
        Set the mocked out syspurpose to the given dictionary of values.
        Assumes it is called after syspurposelib.USER_SYSPURPOSE is mocked out.
        :param syspurpose: A dict of values to be set as the syspurpose
        :return: None
        """
        with open(syspurposelib.USER_SYSPURPOSE, "w") as sp_file:
            json.dump(syspurpose, sp_file, ensure_ascii=True)

    def setUp(self):
        syspurpose_patch = patch("syspurpose.files.SyncedStore")
        sp_patch = syspurpose_patch.start()
        self.addCleanup(sp_patch.stop)
        super(TestAddonsCommand, self).setUp()
        argv_patcher = patch.object(sys, "argv", ["subscription-manager", "addons"])
        argv_patcher.start()
        self.addCleanup(argv_patcher.stop)
        syspurposelib.USER_SYSPURPOSE = self.write_tempfile("{}").name

    def tearDown(self):
        super(TestAddonsCommand, self).tearDown()
        syspurposelib.USER_SYSPURPOSE = "/etc/rhsm/syspurpose/syspurpose.json"

    def test_view(self):
        self._test_no_exception([])

    def test_add(self):
        self._test_no_exception(["--add", "test"])

    def test_add_and_remove(self):
        self._test_exception(["--add", "test", "--remove", "something_else"])

    def test_remove(self):
        self._test_no_exception(["--remove", "test"])

    def test_unset(self):
        self._test_no_exception(["--unset"])

    def test_unset_and_add_and_remove(self):
        self._test_exception(["--add", "test", "--remove", "item", "--unset"])

    def test_add_valid_value(self):
        with patch.object(self.cc, "_get_valid_fields") as mock_get_valid_fields:
            mock_get_valid_fields.return_value = {"addons": ["ADDON1", "ADDON3", "ADDON2"]}
            self.assertTrue(self.cc._is_provided_value_valid("ADDON1"))
            with Capture() as cap:
                self.assertEqual(self.cc._are_provided_values_valid(["ADDON1"]), [])
            self.assertNotIn("Warning: Provided value", cap.out)

    def test_add_invalid_value(self):
        with patch.object(self.cc, "_get_valid_fields") as mock_get_valid_fields:
            mock_get_valid_fields.return_value = {"addons": ["ADDON1", "ADDON3", "ADDON2"]}
            self.assertFalse(self.cc._is_provided_value_valid("test"))
            with Capture() as cap:
                self.assertEqual(self.cc._are_provided_values_valid(["test"]), ["test"])
            self.assertIn("Warning: Provided value", cap.out)

    def test_no_valid_values(self):
        with ExitStack() as stack:
            mock_get_valid_fields = stack.enter_context(patch.object(self.cc, "_get_valid_fields"))
            cap = stack.enter_context(Capture())
            mock_get_valid_fields.return_value = {"addons": []}
            self.assertFalse(self.cc._is_provided_value_valid("test"))
            self.assertIn("Warning: This organization does not have", cap.out)
