"""Test fixtures: a FakeEngine that satisfies the route contract without loading
a real model, plus a TestClient wired to it."""
import sys
from pathlib import Path

import pytest

_ROOT = Path(__file__).resolve().parent.parent.parent
sys.path.insert(0, str(_ROOT / "src"))
sys.path.insert(0, str(_ROOT / "compute_server"))

import os
os.environ.setdefault("VOXCAST_DATA_DIR",
                      str(Path(__file__).parent / "_data"))

from app.config import ServerConfig  # noqa: E402
from app.main import create_app  # noqa: E402


class FakeService:
    def __init__(self, text="hello world", ready=True):
        self._text = text
        self.is_ready = ready
        self.device = "cpu"
        self.fell_back_to_cpu = False
        self.file_calls = []
        self.window_calls = 0

    async def transcribe_file(self, path, *, language=None, with_timestamps=False,
                              on_progress=None, multilingual=False):
        self.file_calls.append(
            {"language": language, "with_timestamps": with_timestamps,
             "multilingual": multilingual})
        if on_progress:
            on_progress(0.5)
            on_progress(1.0)
        if not self._text:
            return "", {}
        meta = {
            "duration": 3.0, "language": language or "en",
            "segments": [{"start": 0.0, "end": 1.0, "text": self._text}]
            if with_timestamps else [],
        }
        return self._text, meta

    def transcribe_window_sync(self, audio, language):
        self.window_calls += 1
        return [{"raw": " hello", "norm": "hello", "end": 0.5}]

    async def stop(self):
        pass

    def set_model(self, name):
        pass

    def set_compute_device(self, dev):
        pass

    async def start(self):
        self.is_ready = True


class _Admission:
    async def __aenter__(self):
        return self

    async def __aexit__(self, *exc):
        return False


class FakeUsage:
    def __init__(self):
        self.records = []

    def record(self, principal, audio_seconds, model, request_id):
        self.records.append((principal.id, audio_seconds, model, request_id))


class FakeEngine:
    ALL_TIERS = ("base", "small", "medium", "large-v3-turbo")

    def __init__(self, service=None):
        self.service = service or FakeService()
        self.usage = FakeUsage()
        self._downloaded = {"small"}
        self._active = "small"
        self._test_prestarted = True  # skip lifespan start()
        self.switch_calls = []
        self.download_calls = []

    @property
    def is_ready(self):
        return self.service.is_ready

    def model_exists(self, name):
        return name in self._downloaded

    def models_info(self):
        return [
            {"id": n, "downloaded": n in self._downloaded,
             "loaded": n == self._active and self.is_ready,
             "downloading": False, "size_bytes": 1000, "vram_mb": 2000}
            for n in self.ALL_TIERS
        ]

    async def download_model(self, name):
        self.download_calls.append(name)
        self._downloaded.add(name)

    async def switch_model(self, name):
        self.switch_calls.append(name)
        if name not in self._downloaded:
            await self.download_model(name)
        self._active = name

    def admit(self):
        return _Admission()

    @property
    def queue_depth(self):
        return 0

    def status(self):
        return {
            "server_version": "1.0.0", "ready": self.is_ready,
            "model": self._active, "device": self.service.device,
            "fell_back_to_cpu": False,
            "gpu": {"vram_mb": 8000, "cuda": True},
            "queue_depth": 0, "models": self.models_info(),
            "uptime_s": 1, "update_available": None,
        }

    async def start(self):
        pass

    async def stop(self):
        pass


@pytest.fixture
def fake_engine():
    return FakeEngine()


@pytest.fixture
def app(fake_engine):
    cfg = ServerConfig(api_key="testkey", host="127.0.0.1",
                       max_sync_audio_s=600, queue_size=8)
    return create_app(cfg, engine=fake_engine)


@pytest.fixture
def client(app):
    from fastapi.testclient import TestClient
    with TestClient(app) as c:
        yield c


@pytest.fixture
def auth_headers():
    return {"Authorization": "Bearer testkey"}
