"""Tests for statistics router (/api/statistics)."""
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from src.backend.models.orm.user import User
from src.backend.models.orm.measurement import Measurement
from src.backend.tests.conftest import auth_headers, create_test_recipe


async def _seed_measurements(
    client: AsyncClient,
    tec_user: User,
    recipe_id: int,
    values: list[float],
) -> tuple[int, int]:
    """Create measurements and return (subtask_id, version_id)."""
    tasks_resp = await client.get(
        f"/api/recipes/{recipe_id}/tasks", headers=auth_headers(tec_user)
    )
    task = tasks_resp.json()[0]
    subtask_id = task["subtasks"][0]["id"]
    version_id = task["version_id"]

    for val in values:
        await client.post(
            "/api/measurements/",
            headers=auth_headers(tec_user),
            json={
                "subtask_id": subtask_id,
                "version_id": version_id,
                "value": val,
            },
        )
    return subtask_id, version_id


class TestSummary:
    """GET /api/statistics/summary tests."""

    async def test_get_statistics_by_recipe(
        self,
        client: AsyncClient,
        measurement_tec_user: User,
        metrologist_user: User,
        db_session: AsyncSession,
    ):
        """Metrologist can get summary statistics."""
        recipe = await create_test_recipe(
            db_session, measurement_tec_user.id
        )
        await _seed_measurements(
            client, measurement_tec_user, recipe.id,
            [10.0, 10.1, 10.4, 10.6, 9.4],  # pass, pass, warning, fail, fail
        )

        resp = await client.get(
            "/api/statistics/summary",
            headers=auth_headers(metrologist_user),
            params={"recipe_id": recipe.id},
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["total"] == 5
        assert data["pass_count"] >= 0
        assert data["warning_count"] >= 0
        assert data["fail_count"] >= 0
        assert data["pass_rate"] >= 0
        # Total rates should sum to ~100
        total_rate = data["pass_rate"] + data["warning_rate"] + data["fail_rate"]
        assert abs(total_rate - 100.0) < 0.1

    async def test_statistics_require_metrologist(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Non-Metrologist cannot access statistics."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        resp = await client.get(
            "/api/statistics/summary",
            headers=auth_headers(maker_user),
            params={"recipe_id": recipe.id},
        )
        assert resp.status_code == 403

    async def test_statistics_empty(
        self,
        client: AsyncClient,
        metrologist_user: User,
        db_session: AsyncSession,
    ):
        """Statistics on recipe with no measurements returns zeros."""
        recipe = await create_test_recipe(
            db_session, metrologist_user.id
        )
        resp = await client.get(
            "/api/statistics/summary",
            headers=auth_headers(metrologist_user),
            params={"recipe_id": recipe.id},
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["total"] == 0
        assert data["pass_count"] == 0


class TestCapability:
    """GET /api/statistics/capability tests."""

    async def test_capability_indices(
        self,
        client: AsyncClient,
        measurement_tec_user: User,
        metrologist_user: User,
        db_session: AsyncSession,
    ):
        """Capability endpoint returns Cp/Cpk/Pp/Ppk indices."""
        recipe = await create_test_recipe(
            db_session, measurement_tec_user.id
        )
        subtask_id, _ = await _seed_measurements(
            client, measurement_tec_user, recipe.id,
            [9.9, 10.0, 10.1, 9.8, 10.2, 10.0, 9.95, 10.05, 10.1, 9.9],
        )

        resp = await client.get(
            "/api/statistics/capability",
            headers=auth_headers(metrologist_user),
            params={
                "recipe_id": recipe.id,
                "subtask_id": subtask_id,
            },
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["n"] == 10
        assert data["mean"] is not None
        assert data["std_dev"] is not None
        # With UTL=10.5 and LTL=9.5, spread=1.0, Cp should be > 0
        if data["cp"] is not None:
            assert data["cp"] > 0


class TestSPCData:
    """GET /api/statistics/control-chart tests."""

    async def test_spc_data(
        self,
        client: AsyncClient,
        measurement_tec_user: User,
        metrologist_user: User,
        db_session: AsyncSession,
    ):
        """Control chart returns values, mean, UCL, LCL."""
        recipe = await create_test_recipe(
            db_session, measurement_tec_user.id
        )
        subtask_id, _ = await _seed_measurements(
            client, measurement_tec_user, recipe.id,
            [10.0, 10.1, 9.9, 10.05, 9.95],
        )

        resp = await client.get(
            "/api/statistics/control-chart",
            headers=auth_headers(metrologist_user),
            params={
                "recipe_id": recipe.id,
                "subtask_id": subtask_id,
            },
        )
        assert resp.status_code == 200
        data = resp.json()
        assert len(data["values"]) == 5
        assert data["mean"] is not None
        assert data["ucl"] is not None
        assert data["lcl"] is not None
        assert data["ucl"] > data["mean"]
        assert data["lcl"] < data["mean"]


class TestDateFilter:
    """Date filter tests."""

    async def test_statistics_date_filter(
        self,
        client: AsyncClient,
        measurement_tec_user: User,
        metrologist_user: User,
        db_session: AsyncSession,
    ):
        """Date filter parameters are accepted without error."""
        recipe = await create_test_recipe(
            db_session, measurement_tec_user.id
        )
        await _seed_measurements(
            client, measurement_tec_user, recipe.id,
            [10.0, 10.1],
        )

        resp = await client.get(
            "/api/statistics/summary",
            headers=auth_headers(metrologist_user),
            params={
                "recipe_id": recipe.id,
                "date_from": "2020-01-01T00:00:00",
                "date_to": "2099-12-31T23:59:59",
            },
        )
        assert resp.status_code == 200
        # All measurements should be within this wide range
        assert resp.json()["total"] >= 2
