"""Pytest configuration and fixtures for opendeviationbar tests.

Fast-only test suite: all tests must complete in < 30s total.
No ClickHouse, no network I/O, no slow markers.
"""

from __future__ import annotations

import gc
import os

import pytest

# Issue #206: Force UTC for all tests to catch timezone-dependent bugs
os.environ["TZ"] = "UTC"


@pytest.fixture(autouse=True)
def gc_after_test():
    """Force GC after each test to prevent memory accumulation."""
    yield
    gc.collect()


# =============================================================================
# Shared Trade Factories (DRY consolidation)
# =============================================================================


def make_test_trade(
    agg_trade_id: int,
    timestamp_ms: int,
    price: float,
    quantity: float = 1.0,
    is_buyer_maker: bool | None = None,
) -> dict:
    """Create a single test trade dict with all required fields.

    Parameters
    ----------
    agg_trade_id : int
        Aggregate trade ID.
    timestamp_ms : int
        Trade timestamp in milliseconds.
    price : float
        Trade price.
    quantity : float
        Trade quantity (default 1.0).
    is_buyer_maker : bool | None
        If None, alternates based on agg_trade_id parity.
    """
    return {
        "agg_trade_id": agg_trade_id,
        "price": price,
        "quantity": quantity,
        "first_trade_id": agg_trade_id * 10,
        "last_trade_id": agg_trade_id * 10 + 2,
        "timestamp": timestamp_ms,
        "is_buyer_maker": is_buyer_maker if is_buyer_maker is not None else (agg_trade_id % 2 == 0),
    }


def make_test_trades(
    start_id: int,
    count: int,
    base_ts: int = 1_700_000_000_000,
) -> list[dict]:
    """Generate a list of synthetic trade dicts.

    Parameters
    ----------
    start_id : int
        Starting aggregate trade ID.
    count : int
        Number of trades to generate.
    base_ts : int
        Base timestamp in milliseconds (default: 1_700_000_000_000).
    """
    return [
        {
            "agg_trade_id": start_id + i,
            "timestamp": base_ts + i * 100,
            "price": 42000.0 + (i % 10) * 10.0,
            "quantity": 0.1 + (i % 5) * 0.01,
            "is_buyer_maker": i % 2 == 0,
        }
        for i in range(count)
    ]


def assert_stathera_continuity(bars: list) -> None:
    """Assert Stathera invariant: bar[i].last_agg_trade_id + 1 == bar[i+1].first_agg_trade_id.

    Works with both dict bars and object bars (attribute access).
    """
    for i in range(1, len(bars)):
        prev = bars[i - 1]
        curr = bars[i]
        # Support both dict and object access
        if isinstance(prev, dict):
            prev_last = prev["last_agg_trade_id"]
            curr_first = curr["first_agg_trade_id"]
        else:
            prev_last = prev.last_agg_trade_id
            curr_first = curr.first_agg_trade_id
        assert curr_first == prev_last + 1, (
            f"Stathera break at bar {i}: prev.last_agg_trade_id={prev_last}, "
            f"curr.first_agg_trade_id={curr_first}, delta={curr_first - prev_last}"
        )


@pytest.fixture(autouse=True, scope="session")
def setup_threshold_env_vars():
    """Set threshold env vars for tests (Issue #62).

    Production uses 1000/50/100/1, tests use 1/1/1/1 for flexibility.
    """
    originals = {}
    keys = [
        "OPENDEVIATIONBAR_CRYPTO_MIN_THRESHOLD",
        "OPENDEVIATIONBAR_FOREX_MIN_THRESHOLD",
        "OPENDEVIATIONBAR_EQUITIES_MIN_THRESHOLD",
        "OPENDEVIATIONBAR_UNKNOWN_MIN_THRESHOLD",
    ]
    for key in keys:
        originals[key] = os.environ.get(key)
        os.environ[key] = "1"

    try:
        from opendeviationbar.threshold import clear_threshold_cache

        clear_threshold_cache()
    except ImportError:
        pass

    yield

    for key in keys:
        if originals[key] is not None:
            os.environ[key] = originals[key]
        elif key in os.environ:
            del os.environ[key]

    try:
        from opendeviationbar.threshold import clear_threshold_cache

        clear_threshold_cache()
    except ImportError:
        pass
