import unittest
from unittest.mock import MagicMock, patch

from qhub.service.client import HubServiceClient


class TestHubServiceClientRun(unittest.TestCase):
    """Tests for HubServiceClient.run() focusing on $tags and $secrets injection."""

    def setUp(self):
        with patch.object(HubServiceClient, "__init__", lambda self: None):
            self.client = HubServiceClient()

        mock_api = MagicMock()
        mock_api.service_api.start_execution.return_value = MagicMock()
        self.client._api = mock_api

    def _get_passed_request(self):
        return self.client._api.service_api.start_execution.call_args[1]["request"]

    def test_tags_added_to_request(self):
        request = {"input": "data"}
        self.client.run(request, tags=["tag1", "tag2"])

        passed = self._get_passed_request()
        self.assertEqual(passed["$tags"], ["tag1", "tag2"])

    def test_secrets_added_to_request(self):
        request = {"input": "data"}
        self.client.run(request, secrets={"key": "value"})

        passed = self._get_passed_request()
        self.assertEqual(passed["$secrets"], {"key": "value"})

    def test_tags_and_secrets_added_to_request(self):
        request = {"input": "data"}
        self.client.run(request, tags=["t1"], secrets={"k": "v"})

        passed = self._get_passed_request()
        self.assertEqual(passed["$tags"], ["t1"])
        self.assertEqual(passed["$secrets"], {"k": "v"})

    def test_existing_tags_not_overridden(self):
        request = {"input": "data", "$tags": ["original"]}
        self.client.run(request, tags=["override"])

        passed = self._get_passed_request()
        self.assertEqual(passed["$tags"], ["original"])

    def test_existing_secrets_not_overridden(self):
        request = {"input": "data", "$secrets": {"original": "secret"}}
        self.client.run(request, secrets={"override": "secret"})

        passed = self._get_passed_request()
        self.assertEqual(passed["$secrets"], {"original": "secret"})

    def test_existing_tags_preserved_while_secrets_added(self):
        request = {"input": "data", "$tags": ["original"]}
        self.client.run(request, tags=["override"], secrets={"k": "v"})

        passed = self._get_passed_request()
        self.assertEqual(passed["$tags"], ["original"])
        self.assertEqual(passed["$secrets"], {"k": "v"})

    def test_existing_secrets_preserved_while_tags_added(self):
        request = {"input": "data", "$secrets": {"original": "secret"}}
        self.client.run(request, tags=["t1"], secrets={"override": "secret"})

        passed = self._get_passed_request()
        self.assertEqual(passed["$tags"], ["t1"])
        self.assertEqual(passed["$secrets"], {"original": "secret"})

    def test_no_tags_or_secrets_when_none(self):
        request = {"input": "data"}
        self.client.run(request)

        passed = self._get_passed_request()
        self.assertNotIn("$tags", passed)
        self.assertNotIn("$secrets", passed)

    def test_none_tags_not_added(self):
        request = {"input": "data"}
        self.client.run(request, tags=None)

        passed = self._get_passed_request()
        self.assertNotIn("$tags", passed)

    def test_none_secrets_not_added(self):
        request = {"input": "data"}
        self.client.run(request, secrets=None)

        passed = self._get_passed_request()
        self.assertNotIn("$secrets", passed)

    def test_empty_tags_list_added(self):
        request = {"input": "data"}
        self.client.run(request, tags=[])

        passed = self._get_passed_request()
        self.assertEqual(passed["$tags"], [])

    def test_empty_secrets_dict_added(self):
        request = {"input": "data"}
        self.client.run(request, secrets={})

        passed = self._get_passed_request()
        self.assertEqual(passed["$secrets"], {})

    def test_original_request_keys_preserved(self):
        request = {"input": "data", "other": 42}
        self.client.run(request, tags=["t1"], secrets={"k": "v"})

        passed = self._get_passed_request()
        self.assertEqual(passed["input"], "data")
        self.assertEqual(passed["other"], 42)
        self.assertEqual(passed["$tags"], ["t1"])
        self.assertEqual(passed["$secrets"], {"k": "v"})
