import json
import unittest

import httpx

from sotipy import Soti, SotiValidationError


class SotiClientTests(unittest.TestCase):
    BOT_ID = "1006946815050006539"

    def test_constructor_accepts_token_string(self):
        client = Soti("token_123")
        try:
            self.assertEqual(client.api_token, "token_123")
            self.assertEqual(client.site_base_url, "https://flarehub.pro")
            self.assertEqual(client.api_base_url, "https://api.flarehub.pro")
        finally:
            client.close()

    def test_default_domain_split(self):
        seen_hosts = []

        def handler(request: httpx.Request) -> httpx.Response:
            seen_hosts.append(request.url.host)
            if request.url.path == "/api/approved_bots":
                return httpx.Response(200, json=[{"bot_id": self.BOT_ID, "name": "A"}])
            if request.url.path == "/api/v1/health":
                return httpx.Response(200, json={"ok": True, "data": {"status": "healthy"}})
            return httpx.Response(404, json={"error": "not_found"})

        client = Soti("token_123", transport=httpx.MockTransport(handler))
        try:
            bots = client.get_approved_bots()
            health = client.get_api_health()
            self.assertEqual(len(bots), 1)
            self.assertEqual(health["status"], "healthy")
            self.assertIn("flarehub.pro", seen_hosts)
            self.assertIn("api.flarehub.pro", seen_hosts)
        finally:
            client.close()

    def test_post_bot_stats_normalizes_members_alias(self):
        def handler(request: httpx.Request) -> httpx.Response:
            if request.url.path == f"/api/v1/bots/{self.BOT_ID}/stats":
                body = json.loads(request.read().decode("utf-8"))
                self.assertEqual(body["servers"], 10)
                self.assertEqual(body["users"], 20)
                return httpx.Response(200, json={"ok": True, "data": {"ok": True}})
            return httpx.Response(404, json={"error": "not_found"})

        client = Soti("token_123", transport=httpx.MockTransport(handler))
        try:
            result = client.post_bot_stats(self.BOT_ID, {"guilds": 10, "members": 20, "shards": 1})
            self.assertTrue(result["ok"])
        finally:
            client.close()

    def test_validation_error_for_bad_bot_id(self):
        client = Soti("token_123")
        try:
            with self.assertRaises(SotiValidationError):
                client.get_bot_stats("abc")
        finally:
            client.close()

    def test_autopost_post_once(self):
        def handler(request: httpx.Request) -> httpx.Response:
            if request.url.path == f"/api/v1/bots/{self.BOT_ID}/stats":
                return httpx.Response(200, json={"ok": True, "data": {"posted": True}})
            return httpx.Response(404, json={"error": "not_found"})

        client = Soti("token_123", transport=httpx.MockTransport(handler))
        try:
            autopost = (
                client.autopost(bot_id=self.BOT_ID, immediate=False)
                .init_stats(lambda: {"servers": 1, "users": 2, "shards": 1})
                .set_platform("discord.py")
            )
            result = autopost.post_once()
            self.assertTrue(result["posted"])
        finally:
            client.close()


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