"""Shared fixtures for kj_affiliate_widget test cases.

The widget endpoints all depend on an `affiliate.widget.config` row +
caches that must be cleared between tests. Centralising both keeps the
per-suite setUpClass short and the inter-test cleanup consistent.
"""

from odoo.tests import HttpCase

from odoo.addons.kj_affiliate_widget.controllers import widget_api as _wa


class WidgetTestCommon(HttpCase):
    """Base class for widget endpoint tests — sets up one config + clears caches."""

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.company = cls.env.company
        # Reuse an existing internal user without a widget config — see the
        # detailed comment in test_widget_apply.py for why we don't create
        # a fresh user here.
        Cfg = cls.env["affiliate.widget.config"]
        owned = Cfg.search([]).user_id.ids
        cls.affiliate_user = cls.env["res.users"].search([
            ("share", "=", False),
            ("id", "not in", owned),
            ("active", "=", True),
        ], limit=1)
        if not cls.affiliate_user:
            cls.skipTest(cls, "No internal user without an existing widget config")
        cls.job = cls.env["hr.job"].create({
            "name": "Widget Test Job",
            "company_id": cls.company.id,
            "is_published": True,
            "active": True,
        })
        cls.config = Cfg.create({
            "user_id": cls.affiliate_user.id,
            "partner_id": cls.affiliate_user.partner_id.id,
            "widget_key": "test-widget-common-key-001",
            "widget_mode": "inline",
            "is_active": True,
            "filter_mode": "all",
        })

    @staticmethod
    def _reset_widget_caches():
        """Drain every in-process cache + cancel the pending flush timer.

        The event queue arms a `threading.Timer` that fires 10s later on
        a background thread. If a test enqueues events and finishes
        before the timer fires, the timer fires *during a later test*,
        opens its own registry cursor, and collides with that test's
        TestCursor — a flaky cross-test failure. Cancelling the timer
        here (both setUp and tearDown) keeps each test hermetic.
        """
        _wa._widget_rate_cache.clear()
        _wa._impression_cache.clear()
        with _wa._fragment_cache_lock:
            _wa._fragment_cache.clear()
            for k in list(_wa._fragment_cache_stats):
                _wa._fragment_cache_stats[k] = 0
        with _wa._event_queue_lock:
            _wa._event_queue.clear()
            for k in list(_wa._event_stats):
                _wa._event_stats[k] = 0
            timer = _wa._event_flush_timer
            if timer is not None:
                timer.cancel()
                _wa._event_flush_timer = None

    def setUp(self):
        super().setUp()
        self._reset_widget_caches()

    def tearDown(self):
        # Cancel any timer this test armed so it can't fire into the next.
        self._reset_widget_caches()
        super().tearDown()
