"""
Integration tests for the bulk standard-catalog seed endpoint (POST /tests/seed).
"""

import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import create_access_token, hash_password
from app.models.lab import Lab
from app.models.user import User, UserRole
from app.repositories.permission_repository import PermissionRepository


@pytest_asyncio.fixture(autouse=True)
async def seed_perms(db_session: AsyncSession) -> None:
    repo = PermissionRepository()
    await repo.seed_permissions(db_session)


@pytest_asyncio.fixture
async def catalog_lab(db_session: AsyncSession) -> Lab:
    lab = Lab(name="Seed Test Lab", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()
    await db_session.refresh(lab)
    return lab


@pytest_asyncio.fixture
async def admin_token(db_session: AsyncSession, catalog_lab: Lab) -> str:
    admin = User(
        lab_id=catalog_lab.id,
        name="Seed Admin",
        phone="9814000011",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("AdminPass123!"),
        is_active=True,
    )
    db_session.add(admin)
    await db_session.commit()
    await db_session.refresh(admin)
    return create_access_token(
        subject=str(admin.id),
        extra_claims={"phone": admin.phone, "role": admin.role.value, "lab_id": str(catalog_lab.id)},
    )


@pytest_asyncio.fixture
async def general_user_token(db_session: AsyncSession, catalog_lab: Lab) -> str:
    user = User(
        lab_id=catalog_lab.id,
        name="Seed Staff",
        phone="9814000012",
        role=UserRole.GENERAL_USER,
        hashed_password=hash_password("StaffPass123!"),
        is_active=True,
    )
    db_session.add(user)
    await db_session.commit()
    await db_session.refresh(user)
    return create_access_token(
        subject=str(user.id),
        extra_claims={"phone": user.phone, "role": user.role.value, "lab_id": str(catalog_lab.id)},
    )


SEED_PAYLOAD = {
    "categories": [
        {
            "name": "Hematology",
            "tests": [
                {
                    "code": "CBC",
                    "name": "Complete Blood Count (CBC)",
                    "price": 450,
                    "result_type": "composite",
                    "parameters": [
                        {
                            "name": "Hemoglobin",
                            "unit": "g/dL",
                            "price": 225,
                            "ranges": [
                                {"gender": "male", "numeric_low": 13, "numeric_high": 17},
                                {"gender": "female", "numeric_low": 12, "numeric_high": 15},
                            ],
                        },
                        {
                            "name": "Platelet Count",
                            "unit": "10^3/uL",
                            "price": 225,
                            "ranges": [{"numeric_low": 150, "numeric_high": 450}],
                        },
                    ],
                }
            ],
        },
        {
            "name": "X-Ray",
            "tests": [
                {
                    "code": "XR-CHEST",
                    "name": "Chest X-Ray PA + Lateral",
                    "price": 700,
                    "result_type": "composite",
                    "parameters": [{"name": "Impression", "unit": None, "price": 700, "ranges": []}],
                }
            ],
        },
    ]
}


@pytest.mark.asyncio
class TestBulkSeedEndpoint:
    async def test_seed_creates_full_catalog(self, client: AsyncClient, admin_token: str) -> None:
        res = await client.post(
            "/api/v1/tests/seed",
            json=SEED_PAYLOAD,
            headers={"Authorization": f"Bearer {admin_token}"},
        )
        assert res.status_code == 201
        counts = res.json()["data"]
        assert counts == {"categories": 2, "tests": 2, "updated": 0, "params": 3, "ranges": 3}

        # Analyte prices must sum back to the panel price.
        list_res = await client.get(
            "/api/v1/tests",
            params={"q": "CBC", "limit": 10},
            headers={"Authorization": f"Bearer {admin_token}"},
        )
        assert list_res.status_code == 200
        cbc = next(t for t in list_res.json()["data"] if t["code"] == "CBC")
        detail = await client.get(
            f"/api/v1/tests/{cbc['id']}", headers={"Authorization": f"Bearer {admin_token}"}
        )
        params = detail.json()["data"]["parameters"]
        assert sum(float(p["price"] or 0) for p in params) == float(cbc["price"])

    async def test_seed_is_idempotent(self, client: AsyncClient, admin_token: str) -> None:
        headers = {"Authorization": f"Bearer {admin_token}"}
        first = await client.post("/api/v1/tests/seed", json=SEED_PAYLOAD, headers=headers)
        assert first.status_code == 201
        second = await client.post("/api/v1/tests/seed", json=SEED_PAYLOAD, headers=headers)
        assert second.status_code == 201
        counts = second.json()["data"]
        assert counts["tests"] == 0
        assert counts["params"] == 0
        assert counts["ranges"] == 0

    async def test_seed_requires_auth(self, client: AsyncClient) -> None:
        res = await client.post("/api/v1/tests/seed", json=SEED_PAYLOAD)
        assert res.status_code == 401

    async def test_seed_requires_write_permission(self, client: AsyncClient, general_user_token: str) -> None:
        res = await client.post(
            "/api/v1/tests/seed", json=SEED_PAYLOAD, headers={"Authorization": f"Bearer {general_user_token}"}
        )
        assert res.status_code == 403

    async def test_seed_rejects_empty_catalog(self, client: AsyncClient, admin_token: str) -> None:
        res = await client.post(
            "/api/v1/tests/seed",
            json={"categories": []},
            headers={"Authorization": f"Bearer {admin_token}"},
        )
        assert res.status_code == 422
