import io
import json
import unittest
import urllib.error
from unittest.mock import patch

from src.aiel_integrations import IntegrationsClient, IntegrationApiError


class _FakeResponse:
    def __init__(self, body: bytes):
        self._body = body

    def read(self) -> bytes:
        return self._body

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc, tb):
        return False


class IntegrationsClientTests(unittest.TestCase):
    def test_list_parses_connections(self) -> None:
        payload = [
            {
                "connection_id": "c1",
                "workspace_id": "w1",
                "project_id": "p1",
                "provider": "jira",
                "connector": {"id": "jira", "version": "1.0.0"},
                "resource_type": "jira.site",
                "display_name": "Jira Connection",
                "status": "connected",
                "status_reason": None,
                "capabilities": [],
                "allowed_actions": [],
                "granted_actions": [],
                "auth": {"method": "oauth"},
                "metadata": {},
            }
        ]
        body = json.dumps(payload).encode("utf-8")
        with patch("urllib.request.urlopen", return_value=_FakeResponse(body)):
            client = IntegrationsClient(base_url="https://api.example.com", api_key="k")
            items = client.list("w1", "p1")

        self.assertEqual(len(items), 1)
        self.assertEqual(items[0].connection_id, "c1")
        self.assertEqual(items[0].provider, "jira")

    def test_invoke_action_returns_dict(self) -> None:
        body = json.dumps({"ok": True}).encode("utf-8")
        with patch("urllib.request.urlopen", return_value=_FakeResponse(body)):
            client = IntegrationsClient(base_url="https://api.example.com")
            result = client.invoke_action("w1", "p1", "c1", "slack.post_message", {"params": {}})

        self.assertEqual(result.get("ok"), True)

    def test_http_error_raises_integration_error(self) -> None:
        error_body = io.BytesIO(b'{"error": "bad_request"}')
        http_error = urllib.error.HTTPError(
            url="https://api.example.com",
            code=400,
            msg="Bad Request",
            hdrs=None,
            fp=error_body,
        )
        with patch("urllib.request.urlopen", side_effect=http_error):
            client = IntegrationsClient(base_url="https://api.example.com")
            with self.assertRaises(IntegrationApiError) as ctx:
                client.list("w1", "p1")

        self.assertEqual(ctx.exception.status, 400)


if __name__ == "__main__":
    unittest.main()
