"""Pytest configuration and shared fixtures for Sigil unit tests.

PostgreSQL test-DB isolation: data tables are TRUNCATEd before every test so
no data escapes test boundaries. Tests that hold their own psycopg
connections via ``_make_db()`` helpers (instead of the ``db_conn`` fixture)
do not auto-rollback — the autouse truncate keeps them isolated regardless.
"""

from __future__ import annotations

import os

import psycopg
import pytest
import structlog
from psycopg.rows import dict_row

_DATA_TABLES: tuple[str, ...] = (
    "candles",
    "circuit_breaker_events",
    "llm_calls",
    "micro_coin_candidates",
    "micro_cooldowns",
    "micro_digest_reviews",
    "micro_positions",
    "micro_signals",
    "ml_models",
    "execution_events",
    "graduation_attestation",
    "paper_portfolio",
    "paper_positions",
    "paper_trades",
    "symbol_protections",
    "portfolio_snapshots",
    "positions",
    "pump_events",
    "retrain_requests",
    "scheduled_jobs",
    "signals",
    "trade_audit_log",
    "trades",
)


def _truncate_all(dsn: str) -> None:
    with psycopg.connect(dsn, autocommit=True) as conn:
        with conn.cursor() as cur:
            cur.execute(
                f"TRUNCATE {', '.join(_DATA_TABLES)} RESTART IDENTITY CASCADE"
            )


@pytest.fixture(autouse=True)
def _truncate_sigil_test_db(request: pytest.FixtureRequest) -> None:
    """Wipe all sigil_test data tables before every test.

    Runs only when SIGIL_TEST_DATABASE_URL is set (i.e. the DB-backed suite).
    Pure-unit tests that don't hit PG see no overhead beyond the env-var
    check.
    """
    dsn = os.environ.get("SIGIL_TEST_DATABASE_URL")
    if dsn:
        _truncate_all(dsn)


@pytest.fixture(autouse=True)
def _reset_structlog() -> None:
    """Reset structlog config before every test.

    The production ``setup_logging()`` uses ``cache_logger_on_first_use=True``,
    which defeats ``structlog.testing.capture_logs`` once any test (or
    module-load side-effect) has configured structlog globally. Resetting
    to defaults per-test makes log-capture tests deterministic regardless
    of execution order.
    """
    structlog.reset_defaults()


@pytest.fixture(scope="session")
def pg_dsn() -> str:
    return os.environ.get(
        "SIGIL_TEST_DATABASE_URL",
        "postgresql://sigil_app@###_IP/sigil_test",
    )


@pytest.fixture
def db_conn(pg_dsn: str):  # type: ignore[return]
    """Per-test PG connection with auto-rollback isolation."""
    conn = psycopg.connect(pg_dsn, row_factory=dict_row, autocommit=False)  # type: ignore[call-overload]
    yield conn
    conn.rollback()
    conn.close()
