import json
import unittest
from datetime import datetime, timezone
from types import SimpleNamespace
from unittest.mock import AsyncMock, patch

from bot.app.web.admin_api_impl import common as admin_common
from bot.app.web.admin_api_impl import users as admin_users


class FakeSession:
    def __init__(self):
        self.committed = False
        self.rolled_back = False

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc, tb):
        return False

    async def commit(self):
        self.committed = True

    async def rollback(self):
        self.rolled_back = True


class AdminUserResetTrialRouteTests(unittest.IsolatedAsyncioTestCase):
    def _request(self, session: FakeSession):
        return SimpleNamespace(
            app={
                "settings": SimpleNamespace(),
                "async_session_factory": lambda: session,
            },
            match_info={"user_id": "42"},
        )

    async def test_marks_trial_reset_without_deleting_subscription_history(self):
        session = FakeSession()
        request = self._request(session)
        user = SimpleNamespace(user_id=42)

        with (
            patch.object(admin_users, "_require_admin_user_id", return_value=100),
            patch.object(admin_users.user_dal, "get_user_by_id", AsyncMock(return_value=user)),
            patch.object(
                admin_users.user_dal,
                "mark_trial_eligibility_reset",
                AsyncMock(return_value=object()),
            ) as mark_reset,
            patch.object(
                admin_users.subscription_dal,
                "delete_all_user_subscriptions",
                AsyncMock(),
            ) as delete_all,
            patch.object(
                admin_users.message_log_dal, "create_message_log_no_commit", AsyncMock()
            ) as log,
            patch.object(
                admin_users, "_invalidate_after_admin_user_mutation", AsyncMock()
            ) as invalidate,
        ):
            response = await admin_users.admin_user_reset_trial_route(request)

        self.assertEqual(response.status, 200)
        self.assertEqual(json.loads(response.text)["ok"], True)
        mark_reset.assert_awaited_once_with(session, 42)
        delete_all.assert_not_awaited()
        log_payload = log.await_args.args[1]
        self.assertEqual(log_payload["event_type"], "admin_reset_trial_webapp")
        self.assertEqual(log_payload["target_user_id"], 42)
        invalidate.assert_awaited_once()
        self.assertTrue(session.committed)
        self.assertFalse(session.rolled_back)


class AdminUserTrialPresentationTests(unittest.TestCase):
    def test_trial_subscription_serializes_display_label(self):
        start_at = datetime(2026, 1, 2, 3, 4, tzinfo=timezone.utc)
        end_at = datetime(2026, 1, 9, 3, 4, tzinfo=timezone.utc)
        sub = SimpleNamespace(
            subscription_id=7,
            panel_user_uuid="panel-user",
            panel_subscription_uuid=None,
            start_date=start_at,
            end_date=end_at,
            duration_months=None,
            is_active=False,
            status_from_panel="EXPIRED",
            traffic_limit_bytes=10,
            traffic_used_bytes=2,
            tier_baseline_bytes=0,
            topup_balance_bytes=0,
            premium_used_bytes=0,
            premium_baseline_bytes=0,
            premium_topup_balance_bytes=0,
            premium_topup_used_bytes=0,
            premium_bonus_bytes=0,
            regular_bonus_bytes=0,
            regular_unlimited_override=False,
            premium_unlimited_override=False,
            premium_is_limited=False,
            tariff_key=None,
            auto_renew_enabled=False,
            provider="trial",
            is_throttled=False,
        )

        payload = admin_common._serialize_subscription(sub)

        self.assertTrue(payload["is_trial"])
        self.assertEqual(payload["display_label"], "Trial")
        self.assertIsNone(payload["tariff_key"])

    def test_trial_summary_includes_usage_dates_and_reset_marker(self):
        first_at = datetime(2026, 1, 2, 3, 4, tzinfo=timezone.utc)
        latest_at = datetime(2026, 2, 3, 4, 5, tzinfo=timezone.utc)
        latest_end = datetime(2026, 2, 10, 4, 5, tzinfo=timezone.utc)
        reset_at = datetime(2026, 3, 1, tzinfo=timezone.utc)
        user = SimpleNamespace(trial_eligibility_reset_at=reset_at)
        trial_subs = [
            SimpleNamespace(
                start_date=first_at,
                end_date=datetime(2026, 1, 9, tzinfo=timezone.utc),
            ),
            SimpleNamespace(start_date=latest_at, end_date=latest_end, is_active=True),
        ]

        payload = admin_users._serialize_trial_summary(user, trial_subs)

        self.assertTrue(payload["used"])
        self.assertTrue(payload["active"])
        self.assertEqual(payload["count"], 2)
        self.assertEqual(payload["first_activated_at"], first_at.isoformat())
        self.assertEqual(payload["latest_activated_at"], latest_at.isoformat())
        self.assertEqual(payload["latest_end_date"], latest_end.isoformat())
        self.assertEqual(payload["last_reset_at"], reset_at.isoformat())


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