import unittest
from unittest.mock import patch

from weibo_image_rescue.globalping import execute


class DummyProgressBar:
    def __init__(self, *args, **kwargs):
        pass

    def update(self, _):
        pass

    def close(self):
        pass


class TestGlobalpingExecute(unittest.TestCase):
    def test_unique(self):
        items = ["a", "b", "a"]
        result = execute.unique(items)
        self.assertEqual(set(result), {"a", "b"})

    def test_unique_ips_preserves_order(self):
        self.assertEqual(
            execute.unique_ips(["1.1.1.1", "2.2.2.2", "1.1.1.1", "3.3.3.3"]),
            ["1.1.1.1", "2.2.2.2", "3.3.3.3"],
        )

    def test_get_cdn_collects_from_provider(self):
        class Provider:
            def locations(self):
                return ["asia", "asia", "europe"]

            def resolve(self, hostname, locations):
                self.last_locations = locations
                if hostname == "wx1.sinaimg.cn":
                    return ["1.1.1.1", "2.2.2.2"]
                return ["2.2.2.2", "3.3.3.3"]

        provider = Provider()
        with patch(
            "weibo_image_rescue.globalping.execute.Client", return_value=provider
        ), patch("weibo_image_rescue.globalping.execute.tqdm", DummyProgressBar):
            result = execute.get_cdn(["wx1.sinaimg.cn", "wx2.sinaimg.cn"], force=True)

        self.assertEqual(set(result), {"1.1.1.1", "2.2.2.2", "3.3.3.3"})
        self.assertEqual(set(provider.last_locations), {"asia", "europe"})

    def test_get_cdn_fallbacks_to_local_dns_when_provider_has_no_results(self):
        class Provider:
            def locations(self):
                return ["asia"]

            def resolve(self, hostname, locations):
                raise RuntimeError("globalping unavailable")

        provider = Provider()

        def fake_gethostbyname_ex(hostname):
            if hostname == "wx1.sinaimg.cn":
                return (hostname, [], ["4.4.4.4", "5.5.5.5"])
            return (hostname, [], ["5.5.5.5", "6.6.6.6"])

        with patch(
            "weibo_image_rescue.globalping.execute.Client", return_value=provider
        ), patch(
            "weibo_image_rescue.globalping.execute.tqdm", DummyProgressBar
        ), patch(
            "weibo_image_rescue.globalping.execute.socket.gethostbyname_ex",
            side_effect=fake_gethostbyname_ex,
        ):
            result = execute.get_cdn(["wx1.sinaimg.cn", "wx2.sinaimg.cn"], force=True)

        self.assertEqual(result, ["4.4.4.4", "5.5.5.5", "6.6.6.6"])

    def test_get_cdn_wraps_location_errors(self):
        class Provider:
            def locations(self):
                raise RuntimeError("boom")

        with patch(
            "weibo_image_rescue.globalping.execute.Client", return_value=Provider()
        ):
            with self.assertRaises(Exception) as cm:
                execute.get_cdn(["wx1.sinaimg.cn"])

        self.assertIn("failed to get locations", str(cm.exception))


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