import asyncio
import unittest
from unittest.mock import AsyncMock, Mock, patch

from weibo_image_rescue import custom_transport


class TestBuildDirectIpUrl(unittest.TestCase):
    def test_build_direct_ip_url_with_ipv6_and_port(self):
        direct_url, host = custom_transport._build_direct_ip_url(
            "https://wx1.sinaimg.cn:443/mw690/a.jpg?x=1",
            "2408:4004:1000::101f",
        )
        self.assertEqual(
            direct_url,
            "https://[2408:4004:1000::101f]:443/mw690/a.jpg?x=1",
        )
        self.assertEqual(host, "wx1.sinaimg.cn")

    def test_build_direct_ip_url_invalid_url(self):
        with self.assertRaises(ValueError):
            custom_transport._build_direct_ip_url("not-a-url", "1.2.3.4")


class TestRequest(unittest.TestCase):
    def test_request_dns_success(self):
        response = Mock(status_code=200, headers={"content-type": "image/jpeg"}, content=b"x")
        client = AsyncMock()
        client.get = AsyncMock(return_value=response)
        client_cm = AsyncMock()
        client_cm.__aenter__.return_value = client

        with patch(
            "weibo_image_rescue.custom_transport.httpx.AsyncHTTPTransport"
        ) as transport_cls, patch(
            "weibo_image_rescue.custom_transport.httpx.AsyncClient",
            return_value=client_cm,
        ) as async_client_cls:
            result = asyncio.run(
                custom_transport.request(
                    "https://wx1.sinaimg.cn/mw690/a.jpg",
                    {"Accept": "image/*"},
                    ip=None,
                    timeout=3.0,
                )
            )

        self.assertEqual(result.status, 200)
        self.assertEqual(result.ip, "dns")
        self.assertEqual(result.url, "https://wx1.sinaimg.cn/mw690/a.jpg")
        self.assertEqual(result.body, b"x")
        client.get.assert_awaited_once_with("https://wx1.sinaimg.cn/mw690/a.jpg")
        kwargs = async_client_cls.call_args.kwargs
        self.assertEqual(kwargs["headers"], {"Accept": "image/*"})
        self.assertEqual(kwargs["transport"], transport_cls.return_value)
        self.assertEqual(kwargs["timeout"], 3.0)

    def test_request_dns_exception(self):
        client = AsyncMock()
        client.get = AsyncMock(side_effect=RuntimeError("boom"))
        client_cm = AsyncMock()
        client_cm.__aenter__.return_value = client

        with patch(
            "weibo_image_rescue.custom_transport.httpx.AsyncClient",
            return_value=client_cm,
        ):
            result = asyncio.run(
                custom_transport.request(
                    "https://wx1.sinaimg.cn/mw690/a.jpg",
                    {"Accept": "image/*"},
                    ip=None,
                )
            )

        self.assertIsNotNone(result.err)
        self.assertEqual(result.ip, "dns")

    def test_request_direct_ip_success_sets_host_header(self):
        response = Mock(status_code=200, headers={"content-type": "image/jpeg"}, content=b"ok")
        client = AsyncMock()
        client.get = AsyncMock(return_value=response)
        client_cm = AsyncMock()
        client_cm.__aenter__.return_value = client
        headers = {"Accept": "image/*"}

        with patch(
            "weibo_image_rescue.custom_transport.httpx.AsyncHTTPTransport"
        ), patch(
            "weibo_image_rescue.custom_transport.httpx.AsyncClient",
            return_value=client_cm,
        ) as async_client_cls:
            result = asyncio.run(
                custom_transport.request(
                    "https://wx1.sinaimg.cn/mw690/a.jpg",
                    headers,
                    ip="1.2.3.4",
                    timeout=2.5,
                )
            )

        self.assertEqual(result.status, 200)
        self.assertEqual(result.ip, "1.2.3.4")
        client.get.assert_awaited_once_with("https://1.2.3.4/mw690/a.jpg")
        called_headers = async_client_cls.call_args.kwargs["headers"]
        self.assertEqual(called_headers["Host"], "wx1.sinaimg.cn")
        self.assertEqual(headers, {"Accept": "image/*"})
        self.assertEqual(async_client_cls.call_args.kwargs["verify"], False)

    def test_request_direct_ip_invalid_url_returns_error(self):
        result = asyncio.run(
            custom_transport.request(
                "not-a-url",
                {"Accept": "image/*"},
                ip="1.2.3.4",
            )
        )
        self.assertIsNotNone(result.err)
        self.assertEqual(result.ip, "1.2.3.4")
        self.assertEqual(result.url, "not-a-url")


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