import unittest
from types import SimpleNamespace
from unittest.mock import AsyncMock

from bot.services.panel_dry_run_api_service import PanelDryRunApiService


def _settings(**overrides):
    values = {
        "PANEL_API_URL": "https://panel.example.test/api",
        "PANEL_API_KEY": "panel-key",
        "PANEL_DRY_RUN_VALIDATE_REMOTE": False,
        "PANEL_DRY_RUN_SYNTHETIC_CREATE": True,
        "PANEL_USER_CACHE_TTL_SECONDS": 0,
        "PANEL_DEVICES_CACHE_TTL_SECONDS": 0,
        "PANEL_ALL_USERS_CACHE_TTL_SECONDS": 0,
        "PANEL_ALL_USERS_PAGE_SIZE": 1000,
        "REDIS_KEY_PREFIX": "tests",
        "USER_HWID_DEVICE_LIMIT": None,
    }
    values.update(overrides)
    return SimpleNamespace(**values)


class PanelDryRunApiServiceTests(unittest.IsolatedAsyncioTestCase):
    async def test_update_user_details_returns_synthetic_success_without_http_write(self):
        service = PanelDryRunApiService(_settings())
        service._request_once = AsyncMock()

        result = await service.update_user_details_on_panel(
            "user-uuid",
            {"trafficLimitBytes": 1024, "trafficLimitStrategy": "NO_RESET"},
        )

        self.assertEqual(result["uuid"], "user-uuid")
        self.assertTrue(result["dryRun"])
        self.assertEqual(result["trafficLimitBytes"], 1024)
        service._request_once.assert_not_awaited()

    async def test_update_user_details_rejects_invalid_payload(self):
        service = PanelDryRunApiService(_settings())
        service._request_once = AsyncMock()

        result = await service.update_user_details_on_panel(
            "user-uuid",
            {"trafficLimitBytes": -1, "trafficLimitStrategy": "NO_RESET"},
        )

        self.assertIsNone(result)
        service._request_once.assert_not_awaited()

    async def test_remote_validation_blocks_missing_panel_user(self):
        service = PanelDryRunApiService(_settings(PANEL_DRY_RUN_VALIDATE_REMOTE=True))
        service._request_once = AsyncMock(
            return_value={"error": True, "status_code": 404, "details": {"errorCode": "A062"}}
        )

        result = await service.update_user_details_on_panel(
            "missing-user",
            {"trafficLimitBytes": 1024, "trafficLimitStrategy": "NO_RESET"},
        )

        self.assertIsNone(result)
        service._request_once.assert_awaited_once()

    async def test_create_panel_user_returns_synthetic_user(self):
        service = PanelDryRunApiService(_settings())
        service._request_once = AsyncMock()

        result = await service.create_panel_user(
            username_on_panel="tg_42",
            telegram_id=42,
            default_traffic_limit_bytes=2048,
            default_traffic_limit_strategy="NO_RESET",
        )

        panel_user = result["response"]
        self.assertTrue(panel_user["dryRun"])
        self.assertEqual(panel_user["username"], "tg_42")
        self.assertIn("uuid", panel_user)
        self.assertTrue(
            panel_user["subscriptionUrl"].startswith("https://panel.example.test/api/sub/")
        )
        self.assertTrue(panel_user["subscriptionUrl"].endswith(panel_user["shortUuid"]))
        service._request_once.assert_not_awaited()

    async def test_happ_encrypt_post_stays_live(self):
        service = PanelDryRunApiService(_settings())
        service._request_once = AsyncMock(
            return_value={"response": {"encryptedLink": "happ://crypt4/test"}}
        )

        result = await service.encrypt_happ_link("https://panel.example.test/sub/abc")

        self.assertEqual(result, "happ://crypt4/test")
        service._request_once.assert_awaited_once()


if __name__ == "__main__":  # pragma: no cover
    unittest.main()
