"""
Comprehensive end-to-end smoke test verifying all endpoints work seamlessly
without requiring explicit lab_id in a single-tenant environment.
"""

from decimal import Decimal

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

from app.core.security import 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
async def setup_env(db_session: AsyncSession) -> tuple[Lab, User, str]:
    """Seed permissions, default lab, superadmin, and get a bearer token."""
    await PermissionRepository().seed_permissions(db_session)

    lab = Lab(name="Munal Central Lab", address="Kathmandu, Nepal")
    db_session.add(lab)
    await db_session.flush()

    superadmin = User(
        lab_id=lab.id,
        name="Super Admin",
        phone="9800000000",
        email="admin@munal.com",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("AdminPassword123!"),
        is_active=True,
    )
    db_session.add(superadmin)
    await db_session.commit()
    await db_session.refresh(lab)
    await db_session.refresh(superadmin)
    return lab, superadmin, "AdminPassword123!"


@pytest.mark.asyncio
class TestAllEndpointsWithoutLabId:
    """Test suite ensuring all endpoints work smoothly without requiring lab_id."""

    async def test_auth_login_methods_without_lab_id(
        self, client: AsyncClient, setup_env: tuple[Lab, User, str]
    ) -> None:
        """Verify login works via phone, email, or username without lab_id."""
        _, _, password = setup_env

        # 1. Login via phone
        res_phone = await client.post(
            "/api/v1/auth/login",
            json={"phone": "9800000000", "password": password},
        )
        assert res_phone.status_code == 200, res_phone.text
        assert "access_token" in res_phone.json()["data"]

        # 2. Login via email
        res_email = await client.post(
            "/api/v1/auth/login",
            json={"email": "admin@munal.com", "password": password},
        )
        assert res_email.status_code == 200, res_email.text
        assert "access_token" in res_email.json()["data"]

    async def test_crud_workflows_without_explicit_lab_id(
        self, client: AsyncClient, setup_env: tuple[Lab, User, str], db_session: AsyncSession
    ) -> None:
        """Verify all domain CRUDs succeed without providing lab_id."""
        lab, _, password = setup_env

        # 1. Login
        login_res = await client.post(
            "/api/v1/auth/login",
            json={"phone": "9800000000", "password": password},
        )
        token = login_res.json()["data"]["access_token"]
        headers = {"Authorization": f"Bearer {token}"}

        # 2. Users endpoint: Create user without lab_id
        user_res = await client.post(
            "/api/v1/users",
            headers=headers,
            json={
                "name": "Dr. Phlebotomist",
                "phone": "9849999999",
                "email": "phleb@munal.com",
                "role": "phlebotomist",
                "password": "Password123!",
            },
        )
        assert user_res.status_code == 201, user_res.text
        user_data = user_res.json()["data"]
        assert user_data["lab_id"] == str(lab.id)

        # 3. Patients endpoint: Create patient without lab_id
        patient_res = await client.post(
            "/api/v1/patients",
            headers=headers,
            json={
                "name": "Hari Bahadur",
                "phone": "9812345678",
                "gender": "male",
                "age": 45,
            },
        )
        assert patient_res.status_code == 201, patient_res.text
        patient_data = patient_res.json()["data"]
        assert patient_data["lab_id"] == str(lab.id)
        patient_id = patient_data["id"]

        # 4. Test Catalog: Create category without lab_id
        cat_res = await client.post(
            "/api/v1/test-categories",
            headers=headers,
            json={"name": "Biochemistry", "description": "Blood chemistry"},
        )
        assert cat_res.status_code == 201, cat_res.text
        cat_id = cat_res.json()["data"]["id"]

        # 5. Test Catalog: Create test without lab_id
        test_res = await client.post(
            "/api/v1/tests",
            headers=headers,
            json={
                "category_id": cat_id,
                "name": "Blood Glucose Fasting",
                "code": "BGF",
                "price": 250.00,
                "result_type": "numeric",
            },
        )
        assert test_res.status_code == 201, test_res.text
        test_id = test_res.json()["data"]["id"]

        # 6. Packages: Create package without lab_id
        pkg_res = await client.post(
            "/api/v1/packages",
            headers=headers,
            json={
                "name": "Diabetes Screening Package",
                "code": "DSP01",
                "price": 1200.00,
            },
        )
        assert pkg_res.status_code == 201, pkg_res.text
        pkg_id = pkg_res.json()["data"]["id"]

        # 7. Appointments: Create slot and appointment without lab_id
        from datetime import UTC, datetime, timedelta

        start_time = datetime.now(UTC) + timedelta(days=1)
        end_time = start_time + timedelta(hours=2)
        slot_res = await client.post(
            "/api/v1/appointment-slots",
            headers=headers,
            json={
                "start_at": start_time.isoformat(),
                "end_at": end_time.isoformat(),
                "capacity": 10,
            },
        )
        assert slot_res.status_code == 201, slot_res.text
        slot_id = slot_res.json()["data"]["id"]

        apt_res = await client.post(
            "/api/v1/appointments",
            headers=headers,
            json={
                "patient_id": patient_id,
                "slot_id": slot_id,
                "booked_via": "online",
            },
        )
        assert apt_res.status_code == 201, apt_res.text
        apt_id = apt_res.json()["data"]["id"]

        # 8. Orders: Create order without lab_id
        order_res = await client.post(
            "/api/v1/orders",
            headers=headers,
            json={
                "patient_id": patient_id,
                "appointment_id": apt_id,
                "test_ids": [test_id],
                "package_ids": [pkg_id],
            },
        )
        assert order_res.status_code == 201, order_res.text
        order_data = order_res.json()["data"]
        assert order_data["lab_id"] == str(lab.id)
        assert Decimal(str(order_data["total_amount"])) == Decimal("1450.00")

        # 9. Verify GET endpoints
        assert (await client.get("/api/v1/labs", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/users", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/patients", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/test-categories", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/tests", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/packages", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/appointment-slots", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/appointments", headers=headers)).status_code == 200
        assert (await client.get("/api/v1/orders", headers=headers)).status_code == 200
