"""
Integration tests for created_from / created_to range filters (FY views).

Covers patients, orders, and bills list endpoints with inclusive-from /
exclusive-to semantics on created_at.
"""

from datetime import UTC, datetime

import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy import update
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.patient import Patient
from app.models.test import (
    Test as LabTest,
)
from app.models.test import (
    TestCategory as LabCategory,
)
from app.models.test import (
    TestResultType as LabResultType,
)
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 range_lab(db_session: AsyncSession) -> Lab:
    """Create a primary test lab."""
    lab = Lab(name="Range Filter Lab", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()
    await db_session.refresh(lab)
    return lab


@pytest_asyncio.fixture
async def range_admin_token(db_session: AsyncSession, range_lab: Lab) -> str:
    """Create an admin user and return their Bearer token."""
    admin = User(
        lab_id=range_lab.id,
        name="Range Admin",
        phone="9813000099",
        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(range_lab.id),
        },
    )


async def _make_patient(
    client: AsyncClient, headers: dict[str, str], lab: Lab, name: str, phone: str
) -> dict:
    res = await client.post(
        "/api/v1/patients",
        json={"lab_id": str(lab.id), "name": name, "gender": "male", "phone": phone, "age": 30},
        headers=headers,
    )
    assert res.status_code == 201
    return res.json()["data"]


@pytest_asyncio.fixture
async def range_test(db_session: AsyncSession, range_lab: Lab) -> LabTest:
    """Create a billable catalog test for order creation."""
    cat = LabCategory(lab_id=range_lab.id, name="Range Category")
    db_session.add(cat)
    await db_session.flush()
    test = LabTest(
        lab_id=range_lab.id,
        category_id=cat.id,
        name="Range Panel",
        code="RNG",
        price=450.0,
        result_type=LabResultType.NUMERIC,
    )
    db_session.add(test)
    await db_session.commit()
    await db_session.refresh(test)
    return test


async def _make_order(
    client: AsyncClient, headers: dict[str, str], lab: Lab, patient_id: str, test_id: str
) -> dict:
    res = await client.post(
        "/api/v1/orders",
        json={"lab_id": str(lab.id), "patient_id": patient_id, "test_ids": [test_id]},
        headers=headers,
    )
    assert res.status_code == 201
    return res.json()["data"]


@pytest.mark.asyncio
class TestCreatedRangeFilters:
    """Range filters narrow list results by creation timestamp."""

    async def test_patients_created_range_inclusive_from_exclusive_to(
        self, client: AsyncClient, range_admin_token: str, range_lab: Lab, db_session: AsyncSession
    ) -> None:
        headers = {"Authorization": f"Bearer {range_admin_token}"}
        old = await _make_patient(client, headers, range_lab, "Old Patient", "9813000101")
        new = await _make_patient(client, headers, range_lab, "New Patient", "9813000102")

        await db_session.execute(
            update(Patient)
            .where(Patient.id == old["id"])
            .values(created_at=datetime(2024, 7, 16, 0, 0, 0, tzinfo=UTC))
        )
        await db_session.execute(
            update(Patient)
            .where(Patient.id == new["id"])
            .values(created_at=datetime(2025, 7, 17, 0, 0, 0, tzinfo=UTC))
        )
        await db_session.commit()

        res = await client.get(
            "/api/v1/patients",
            params={"created_from": "2024-07-16T00:00:00+05:45", "created_to": "2025-07-17T00:00:00+05:45"},
            headers=headers,
        )
        assert res.status_code == 200
        payload = res.json()
        assert payload["meta"]["total"] == 1
        assert payload["data"][0]["id"] == old["id"]

        res_all = await client.get("/api/v1/patients", headers=headers)
        assert res_all.json()["meta"]["total"] == 2

    async def test_orders_created_range(
        self, client: AsyncClient, range_admin_token: str, range_lab: Lab, range_test: LabTest
    ) -> None:
        headers = {"Authorization": f"Bearer {range_admin_token}"}
        patient = await _make_patient(client, headers, range_lab, "Range Patient", "9813000103")
        await _make_order(client, headers, range_lab, patient["id"], str(range_test.id))

        res = await client.get(
            "/api/v1/orders",
            params={"created_from": "2000-01-01T00:00:00+00:00", "created_to": "2100-01-01T00:00:00+00:00"},
            headers=headers,
        )
        assert res.status_code == 200
        assert res.json()["meta"]["total"] == 1

        res_empty = await client.get(
            "/api/v1/orders",
            params={"created_from": "2100-01-01T00:00:00+00:00"},
            headers=headers,
        )
        assert res_empty.status_code == 200
        assert res_empty.json()["meta"]["total"] == 0

    async def test_bills_created_range(
        self, client: AsyncClient, range_admin_token: str, range_lab: Lab, range_test: LabTest
    ) -> None:
        headers = {"Authorization": f"Bearer {range_admin_token}"}
        patient = await _make_patient(client, headers, range_lab, "Bill Range Patient", "9813000104")
        order = await _make_order(client, headers, range_lab, patient["id"], str(range_test.id))
        bill_res = await client.post("/api/v1/bills", json={"order_id": order["id"]}, headers=headers)
        assert bill_res.status_code == 201

        res = await client.get(
            "/api/v1/bills",
            params={"created_from": "2000-01-01T00:00:00+00:00", "created_to": "2100-01-01T00:00:00+00:00"},
            headers=headers,
        )
        assert res.status_code == 200
        assert res.json()["meta"]["total"] == 1

        res_empty = await client.get(
            "/api/v1/bills",
            params={"created_to": "2000-01-01T00:00:00+00:00"},
            headers=headers,
        )
        assert res_empty.status_code == 200
        assert res_empty.json()["meta"]["total"] == 0
