from __future__ import annotations

from collections.abc import Generator
from datetime import UTC, datetime
from decimal import Decimal

from auth_helpers import install_legacy_header_auth_override
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool

from app.api.deps import get_db
from app.db.base import Base
from app.main import create_app
from app.models.employee import Employee
from app.models.financial_record import ExpenseClaim


def build_client() -> tuple[TestClient, sessionmaker[Session]]:
    engine = create_engine(
        "sqlite+pysqlite:///:memory:",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    Base.metadata.create_all(bind=engine)
    session_factory = sessionmaker(bind=engine, autoflush=False, autocommit=False)
    app = create_app()
    install_legacy_header_auth_override(app)

    def override_db() -> Generator[Session, None, None]:
        db = session_factory()
        try:
            yield db
        finally:
            db.close()

    app.dependency_overrides[get_db] = override_db
    return TestClient(app), session_factory


def seed_claims(db: Session) -> None:
    employee = Employee(
        id="emp-page",
        employee_no="E-PAGE",
        name="Page User",
        email="page-user@example.com",
        position="Analyst",
        grade="P4",
    )
    db.add(employee)
    for index in range(3):
        db.add(
            ExpenseClaim(
                id=f"claim-page-{index}",
                claim_no=f"EXP-PAGE-{index}",
                employee_id=employee.id,
                employee_name=employee.name,
                department_id="dept-page",
                department_name="Market",
                project_code=None,
                expense_type="office",
                reason=f"Office purchase {index}",
                location="Shanghai",
                amount=Decimal("100.00"),
                currency="CNY",
                invoice_count=0,
                occurred_at=datetime(2026, 5, 20 + index, tzinfo=UTC),
                submitted_at=None,
                status="draft",
                approval_stage="draft",
                risk_flags_json=[],
                created_at=datetime(2026, 5, 20 + index, tzinfo=UTC),
                updated_at=datetime(2026, 5, 20 + index, tzinfo=UTC),
            )
        )
    db.commit()


def test_expense_claims_support_page_envelope_and_keep_legacy_list() -> None:
    client, session_factory = build_client()
    with session_factory() as db:
        seed_claims(db)

    headers = {"x-auth-username": "E-PAGE", "x-auth-name": "Page User"}
    legacy_response = client.get("/api/v1/reimbursements/claims", headers=headers)
    assert legacy_response.status_code == 200
    assert isinstance(legacy_response.json(), list)

    page_response = client.get(
        "/api/v1/reimbursements/claims?page=1&page_size=2",
        headers=headers,
    )

    assert page_response.status_code == 200
    payload = page_response.json()
    assert [key for key in payload if key in {"items", "total", "page", "page_size"}] == [
        "items",
        "total",
        "page",
        "page_size",
    ]
    assert len(payload["items"]) == 2
    assert payload["total"] == 3
    assert payload["page"] == 1
    assert payload["page_size"] == 2
    assert payload["total_pages"] == 2
    assert payload["has_next"] is True
    assert payload["has_previous"] is False
    assert payload["items"][0]["employee_no"] == "E-PAGE"
    assert payload["items"][0]["employee_email"] == "page-user@example.com"


def test_employee_directory_supports_backend_pagination() -> None:
    client, _ = build_client()

    response = client.get(
        "/api/v1/employees?page=2&page_size=10",
        headers={"x-auth-username": "admin"},
    )

    assert response.status_code == 200
    payload = response.json()
    assert len(payload["items"]) == 10
    assert payload["total"] >= 30
    assert payload["page"] == 2
    assert payload["page_size"] == 10


def test_budget_allocations_support_backend_pagination() -> None:
    client, _ = build_client()

    response = client.get(
        "/api/v1/budgets/allocations?page=1&page_size=2",
        headers={"x-auth-username": "admin", "x-auth-role-codes": "manager"},
    )

    assert response.status_code == 200
    payload = response.json()
    assert len(payload["items"]) <= 2
    assert payload["total"] >= len(payload["items"])
    assert payload["page"] == 1
    assert payload["page_size"] == 2
