"""
Integration tests for the shared unit-of-measure catalog (GET/POST/PATCH/DELETE /units).
"""

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="Units 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="Units Admin",
        phone="9814000021",
        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="Units Staff",
        phone="9814000022",
        role=UserRole.RECEPTIONIST,
        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)},
    )


@pytest.mark.asyncio
class TestUnitsEndpoints:
    async def test_unit_lifecycle(self, client: AsyncClient, admin_token: str) -> None:
        headers = {"Authorization": f"Bearer {admin_token}"}

        create_res = await client.post("/api/v1/units", json={"name": "drops/mL"}, headers=headers)
        assert create_res.status_code == 201
        unit_id = create_res.json()["data"]["id"]

        list_res = await client.get("/api/v1/units", headers=headers)
        assert list_res.status_code == 200
        assert any(u["name"] == "drops/mL" for u in list_res.json()["data"])

        patch_res = await client.patch(
            f"/api/v1/units/{unit_id}", json={"description": "drops per milliliter"}, headers=headers
        )
        assert patch_res.status_code == 200

        del_res = await client.delete(f"/api/v1/units/{unit_id}", headers=headers)
        assert del_res.status_code == 200

    async def test_duplicate_unit_rejected_case_insensitive(
        self, client: AsyncClient, admin_token: str
    ) -> None:
        headers = {"Authorization": f"Bearer {admin_token}"}
        first = await client.post("/api/v1/units", json={"name": "TestUnit-XYZ/mL"}, headers=headers)
        assert first.status_code == 201
        dup = await client.post("/api/v1/units", json={"name": "testunit-xyz/ml"}, headers=headers)
        assert dup.status_code == 409

    async def test_system_unit_delete_blocked(
        self, client: AsyncClient, db_session: AsyncSession, admin_token: str
    ) -> None:
        from app.repositories.unit_repository import UnitRepository

        await UnitRepository().seed_defaults(db_session, ["mg/dL"])
        await db_session.commit()
        headers = {"Authorization": f"Bearer {admin_token}"}
        list_res = await client.get("/api/v1/units", headers=headers)
        assert list_res.status_code == 200
        system = next(u for u in list_res.json()["data"] if u["name"] == "mg/dL")
        assert system["is_system"] is True
        del_res = await client.delete(f"/api/v1/units/{system['id']}", headers=headers)
        assert del_res.status_code == 409

    async def test_units_require_auth(self, client: AsyncClient) -> None:
        assert (await client.get("/api/v1/units")).status_code == 401
        assert (await client.post("/api/v1/units", json={"name": "x"})).status_code == 401

    async def test_units_require_write_permission(self, client: AsyncClient, general_user_token: str) -> None:
        headers = {"Authorization": f"Bearer {general_user_token}"}
        assert (await client.get("/api/v1/units", headers=headers)).status_code == 200
        res = await client.post("/api/v1/units", json={"name": "x"}, headers=headers)
        assert res.status_code == 403
