"""
Integration tests for Laboratory CRUD endpoints.
"""

from uuid import uuid4

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:
    """Seed permissions for RBAC checks."""
    repo = PermissionRepository()
    await repo.seed_permissions(db_session)


@pytest_asyncio.fixture
async def admin_auth_header(db_session: AsyncSession) -> dict[str, str]:
    """Create an admin user and return authorization header."""
    lab = Lab(name="HQ Lab", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()

    admin = User(
        lab_id=lab.id,
        name="Admin User",
        phone="9811111111",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("Pass123!"),
        is_active=True,
    )
    db_session.add(admin)
    await db_session.commit()

    token = create_access_token(
        subject=str(admin.id),
        extra_claims={"role": admin.role.value, "lab_id": str(admin.lab_id)},
    )
    return {"Authorization": f"Bearer {token}"}


@pytest.mark.asyncio
class TestLabEndpoints:
    """Test suite for Lab CRUD operations."""

    async def test_create_lab_success(self, client: AsyncClient, admin_auth_header: dict[str, str]) -> None:
        payload = {
            "name": "Pokhara Diagnostic Center",
            "address": "New Road, Pokhara",
            "logo_url": "https://storage.munal.test/logos/pokhara.png",
        }
        response = await client.post(
            "/api/v1/labs",
            json=payload,
            headers=admin_auth_header,
        )
        assert response.status_code == 201
        body = response.json()
        assert body["success"] is True
        data = body["data"]
        assert data["name"] == payload["name"]
        assert data["address"] == payload["address"]
        assert data["logo_url"] == payload["logo_url"]
        assert "id" in data

    async def test_list_labs_paginated(
        self, client: AsyncClient, admin_auth_header: dict[str, str], db_session: AsyncSession
    ) -> None:
        # Create additional labs
        db_session.add_all(
            [
                Lab(name="Branch A"),
                Lab(name="Branch B"),
            ]
        )
        await db_session.commit()

        response = await client.get(
            "/api/v1/labs?page=1&limit=10",
            headers=admin_auth_header,
        )
        assert response.status_code == 200
        body = response.json()
        assert body["success"] is True
        assert len(body["data"]) >= 2
        assert "meta" in body
        assert body["meta"]["page"] == 1
        assert body["meta"]["limit"] == 10
        assert body["meta"]["total"] >= 2

    async def test_get_lab_by_id(
        self, client: AsyncClient, admin_auth_header: dict[str, str], db_session: AsyncSession
    ) -> None:
        lab = Lab(name="Biratnagar Center", address="Biratnagar")
        db_session.add(lab)
        await db_session.commit()

        response = await client.get(
            f"/api/v1/labs/{lab.id}",
            headers=admin_auth_header,
        )
        assert response.status_code == 200
        body = response.json()
        assert body["success"] is True
        assert body["data"]["id"] == str(lab.id)
        assert body["data"]["name"] == "Biratnagar Center"

    async def test_get_lab_not_found(self, client: AsyncClient, admin_auth_header: dict[str, str]) -> None:
        random_id = uuid4()
        response = await client.get(
            f"/api/v1/labs/{random_id}",
            headers=admin_auth_header,
        )
        assert response.status_code == 404
        body = response.json()
        assert body["success"] is False
        assert body["error"]["code"] == "NOT_FOUND"

    async def test_update_lab_success(
        self, client: AsyncClient, admin_auth_header: dict[str, str], db_session: AsyncSession
    ) -> None:
        lab = Lab(name="Old Name", address="Old Address")
        db_session.add(lab)
        await db_session.commit()

        response = await client.patch(
            f"/api/v1/labs/{lab.id}",
            json={"name": "New Name", "address": "New Address"},
            headers=admin_auth_header,
        )
        assert response.status_code == 200
        body = response.json()
        assert body["success"] is True
        assert body["data"]["name"] == "New Name"
        assert body["data"]["address"] == "New Address"

    async def test_delete_lab_soft_delete(
        self, client: AsyncClient, admin_auth_header: dict[str, str], db_session: AsyncSession
    ) -> None:
        lab = Lab(name="To Be Deleted")
        db_session.add(lab)
        await db_session.commit()

        # Delete lab
        del_res = await client.delete(
            f"/api/v1/labs/{lab.id}",
            headers=admin_auth_header,
        )
        assert del_res.status_code == 200
        assert del_res.json()["success"] is True

        # Subsequent GET should return 404
        get_res = await client.get(
            f"/api/v1/labs/{lab.id}",
            headers=admin_auth_header,
        )
        assert get_res.status_code == 404
