"""
Health package endpoints.

Management of test packages and bundled test items.
"""

from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, Query, status
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.core.auth_deps import get_current_user, require_permission
from app.core.dependencies import get_db
from app.core.exceptions import ForbiddenException
from app.core.pagination import PaginationParams
from app.core.permissions import PermissionCode
from app.core.responses import PaginatedResponse, SuccessResponse
from app.models.order import OrderPackage, Sample
from app.models.package import TestPackage
from app.models.test import Test
from app.models.user import User
from app.repositories.lab_repository import LabRepository
from app.schemas.package import (
    TestPackageCreate,
    TestPackageDetailResponse,
    TestPackageItemCreate,
    TestPackageItemResponse,
    TestPackageResponse,
    TestPackageUpdate,
)
from app.services.package_service import PackageService

router = APIRouter(prefix="/packages", tags=["Packages"])
_service = PackageService()


@router.get("/public", response_model=SuccessResponse[list[TestPackageResponse]])
async def list_public_packages(
    db: Annotated[AsyncSession, Depends(get_db)],
) -> SuccessResponse[list[TestPackageResponse]]:
    """List active health packages for the public booking page, ordered by actual usage."""
    lab_id = await LabRepository().get_default_lab_id(db)
    popular = await db.execute(
        select(TestPackage, func.count(OrderPackage.id).label("usage_count"))
        .options(selectinload(TestPackage.items))
        .outerjoin(OrderPackage, OrderPackage.package_id == TestPackage.id)
        .where(
            TestPackage.lab_id == lab_id, TestPackage.is_active.is_(True), TestPackage.deleted_at.is_(None)
        )
        .group_by(TestPackage.id)
        .order_by(func.count(OrderPackage.id).desc(), TestPackage.name.asc())
    )
    rows = list(popular.all())
    packages = [row[0] for row in rows]
    ranked = [row[0] for row in rows if row[1] > 0][:4]
    if not ranked:
        # Avoid a fabricated "popular" ordering when no usage history exists.
        import random

        ranked = random.SystemRandom().sample(packages, min(4, len(packages)))
    else:
        ranked.extend(pkg for pkg in packages if pkg not in ranked)
    result = []
    for pkg in ranked:
        item = TestPackageResponse.model_validate(pkg)
        item.test_count = len(pkg.items) if pkg.items else 0
        result.append(item)
    return SuccessResponse(data=result)


@router.get("/public/summary", response_model=SuccessResponse[dict[str, int]])
async def get_public_catalog_summary(
    db: Annotated[AsyncSession, Depends(get_db)],
) -> SuccessResponse[dict[str, int]]:
    """Return public, aggregate catalog and barcode coverage figures."""
    lab_id = await LabRepository().get_default_lab_id(db)
    test_count = await db.scalar(
        select(func.count(Test.id)).where(
            Test.lab_id == lab_id, Test.is_active.is_(True), Test.deleted_at.is_(None)
        )
    )
    specimen_count = await db.scalar(select(func.count(Sample.id)).where(Sample.lab_id == lab_id))
    barcode_count = await db.scalar(
        select(func.count(Sample.id)).where(
            Sample.lab_id == lab_id, Sample.barcode.is_not(None), Sample.barcode != ""
        )
    )
    total = int(specimen_count or 0)
    coverage = round((int(barcode_count or 0) / total) * 100) if total else 0
    return SuccessResponse(
        data={"active_test_count": int(test_count or 0), "barcode_coverage_percent": coverage}
    )


async def _resolve_lab_id(db: AsyncSession, user: User, requested_lab_id: UUID | None) -> UUID:
    if user.is_superadmin:
        if requested_lab_id:
            return requested_lab_id
        if user.lab_id:
            return user.lab_id
        return await LabRepository().get_default_lab_id(db)
    if not user.lab_id:
        return await LabRepository().get_default_lab_id(db)
    if requested_lab_id and requested_lab_id != user.lab_id:
        raise ForbiddenException("Access denied to another lab branch.")
    return user.lab_id


@router.get(
    "",
    response_model=PaginatedResponse[TestPackageResponse],
    status_code=status.HTTP_200_OK,
    summary="List packages",
    description="Retrieve paginated list of health test packages.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_READ))],
)
async def list_packages(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    pagination: Annotated[PaginationParams, Depends()],
    lab_id: UUID | None = Query(None, description="Filter by lab branch ID"),
    is_active: bool | None = Query(None, description="Filter by active status"),
    q: str | None = Query(None, description="Search query across package name or code"),
) -> PaginatedResponse[TestPackageResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    return await _service.list_packages(db, pagination, lab_id=target_lab_id, is_active=is_active, q=q)


@router.post(
    "",
    response_model=SuccessResponse[TestPackageResponse],
    status_code=status.HTTP_201_CREATED,
    summary="Create package",
    description="Create a new bundled health package.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_WRITE))],
)
async def create_package(
    data: TestPackageCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Target branch lab ID"),
) -> SuccessResponse[TestPackageResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    pkg = await _service.create_package(db, data, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data=pkg, message="Package created successfully.")


@router.get(
    "/{package_id}",
    response_model=SuccessResponse[TestPackageDetailResponse],
    status_code=status.HTTP_200_OK,
    summary="Get package details",
    description="Retrieve details and bundled tests of a package.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_READ))],
)
async def get_package(
    package_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Target branch lab ID"),
) -> SuccessResponse[TestPackageDetailResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    pkg = await _service.get_package(db, package_id, lab_id=target_lab_id)
    return SuccessResponse(data=pkg)


@router.patch(
    "/{package_id}",
    response_model=SuccessResponse[TestPackageResponse],
    status_code=status.HTTP_200_OK,
    summary="Update package",
    description="Update package information, pricing, or active state.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_WRITE))],
)
async def update_package(
    package_id: UUID,
    data: TestPackageUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Target branch lab ID"),
) -> SuccessResponse[TestPackageResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    pkg = await _service.update_package(db, package_id, data, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data=pkg, message="Package updated successfully.")


@router.delete(
    "/{package_id}",
    response_model=SuccessResponse[dict[str, str]],
    status_code=status.HTTP_200_OK,
    summary="Delete package",
    description="Soft delete a health package.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_WRITE))],
)
async def delete_package(
    package_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Target branch lab ID"),
) -> SuccessResponse[dict[str, str]]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    await _service.delete_package(db, package_id, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data={"id": str(package_id)}, message="Package deleted successfully.")


@router.post(
    "/{package_id}/items",
    response_model=SuccessResponse[TestPackageItemResponse],
    status_code=status.HTTP_201_CREATED,
    summary="Add test to package",
    description="Add a test item into a package.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_WRITE))],
)
async def add_package_item(
    package_id: UUID,
    data: TestPackageItemCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Target branch lab ID"),
) -> SuccessResponse[TestPackageItemResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    item = await _service.add_item(db, package_id, data, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data=item, message="Test added to package successfully.")


@router.delete(
    "/{package_id}/items/{item_id}",
    response_model=SuccessResponse[dict[str, str]],
    status_code=status.HTTP_200_OK,
    summary="Remove test from package",
    description="Remove an individual test from a package.",
    dependencies=[Depends(require_permission(PermissionCode.PACKAGE_WRITE))],
)
async def remove_package_item(
    package_id: UUID,
    item_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Target branch lab ID"),
) -> SuccessResponse[dict[str, str]]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    await _service.remove_item(db, package_id, item_id, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data={"id": str(item_id)}, message="Test removed from package successfully.")
