"""Фикстуры тестов: in-memory БД и авторизация-заглушка."""

import os
import tempfile
from collections.abc import Iterator
from typing import Any

import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool

from app import services
from app.db import Base
from app.dependencies import get_db, require_user
from app.main import app

detailing = services.detailing

TEST_DB_URL = "sqlite://"

_engine = create_engine(
    TEST_DB_URL,
    connect_args={"check_same_thread": False},
    poolclass=StaticPool,
)
Base.metadata.create_all(_engine)
_test_session_factory = sessionmaker(bind=_engine, expire_on_commit=False)


def _override_get_db() -> Iterator[Session]:
    session = _test_session_factory()
    try:
        yield session
        session.commit()
    except Exception:
        session.rollback()
        raise
    finally:
        session.close()


app.dependency_overrides[get_db] = _override_get_db

AUTH_USER: dict[str, str] = {"user_id": "1", "email": "test@example.com"}
app.dependency_overrides[require_user] = lambda: AUTH_USER

# Вложения в тестах — во временный каталог
_tmpdir = tempfile.mkdtemp(prefix="gntodo-att-")
os.environ.setdefault("ATTACHMENTS_PATH", _tmpdir)


@pytest.fixture(autouse=True)
def _mock_detailing(monkeypatch: Any) -> Iterator[None]:
    """Фоновая детализация в тестах: тестовая БД и без реального вызова Ollama."""
    monkeypatch.setattr(detailing, "get_session_factory", lambda: _test_session_factory)
    # Запрещаем сетевой вызов LLM: propose вернёт None (как при недоступной Ollama).
    # Тесты при необходимости подменяют propose/generate поверх этого.
    monkeypatch.setattr(
        detailing.DetailingService,
        "generate",
        lambda self, prompt: (_ for _ in ()).throw(RuntimeError("LLM отключён в тестах")),
    )


@pytest.fixture(autouse=True)
def _isolate_db() -> Iterator[None]:
    """Чистые таблицы перед каждым тестом (in-memory БД общая на процесс)."""
    conn = _engine.connect()
    trans = conn.begin()
    for table in reversed(Base.metadata.sorted_tables):
        conn.execute(table.delete())
    trans.commit()
    conn.close()
    yield


@pytest.fixture
def client() -> Iterator[TestClient]:
    with TestClient(app) as c:
        yield c
