"""
Laboratory Operating Hours and Holiday / Leave Management API router.
"""

from datetime import date
from typing import Annotated
from uuid import UUID

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

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.permissions import PermissionCode
from app.core.responses import SuccessResponse
from app.models.appointment import LabScheduleConfig
from app.models.lab import Lab
from app.models.user import User
from app.repositories.lab_repository import LabRepository
from app.schemas.schedule import (
    LabHolidayCreate,
    LabHolidayResponse,
    LabScheduleConfigResponse,
    LabScheduleConfigUpdate,
)
from app.services.schedule_service import ScheduleService

router = APIRouter(prefix="/schedule", tags=["Schedule & Holidays"])
_service = ScheduleService()


@router.get("/public", response_model=SuccessResponse[dict[str, object]])
async def get_public_lab_schedule(
    db: Annotated[AsyncSession, Depends(get_db)],
) -> SuccessResponse[dict[str, object]]:
    """Public, read-only laboratory identity and configured walk-in hours."""
    lab = (
        (
            await db.execute(
                select(Lab).where(Lab.deleted_at.is_(None)).order_by(Lab.created_at.asc()).limit(1)
            )
        )
        .scalars()
        .first()
    )
    if lab is None:
        return SuccessResponse(data={})
    schedule = (
        (await db.execute(select(LabScheduleConfig).where(LabScheduleConfig.lab_id == lab.id).limit(1)))
        .scalars()
        .first()
    )
    return SuccessResponse(
        data={
            "lab_name": lab.name,
            "address": lab.address,
            "logo_url": lab.logo_url,
            "open_time": schedule.open_time if schedule else None,
            "close_time": schedule.close_time if schedule else None,
            "operating_days": schedule.operating_days if schedule else None,
            "is_active": schedule.is_active if schedule else False,
        }
    )


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(
    "/config",
    response_model=SuccessResponse[LabScheduleConfigResponse],
    status_code=status.HTTP_200_OK,
    summary="Get lab operating hours and slot configuration",
    dependencies=[Depends(require_permission(PermissionCode.APPOINTMENT_READ))],
)
async def get_schedule_config(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Optional branch lab ID"),
) -> SuccessResponse[LabScheduleConfigResponse]:
    config = await _service.get_config(db, lab_id=await _resolve_lab_id(db, current_user, lab_id))
    return SuccessResponse(data=config)


@router.put(
    "/config",
    response_model=SuccessResponse[LabScheduleConfigResponse],
    status_code=status.HTTP_200_OK,
    summary="Update lab operating hours, slot interval and capacity",
    description="Configure opening time, closing time, slot interval, and active weekdays.",
    dependencies=[Depends(require_permission(PermissionCode.LAB_WRITE))],
)
async def update_schedule_config(
    data: LabScheduleConfigUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Optional branch lab ID"),
) -> SuccessResponse[LabScheduleConfigResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    config = await _service.update_config(db, data, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data=config, message="Laboratory operating schedule updated successfully.")


@router.get(
    "/holidays",
    response_model=SuccessResponse[list[LabHolidayResponse]],
    status_code=status.HTTP_200_OK,
    summary="List laboratory holidays and closures",
    dependencies=[Depends(require_permission(PermissionCode.APPOINTMENT_READ))],
)
async def list_holidays(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    from_date: Annotated[date | None, Query(description="Filter from date (YYYY-MM-DD)")] = None,
    to_date: Annotated[date | None, Query(description="Filter to date (YYYY-MM-DD)")] = None,
    lab_id: UUID | None = Query(None, description="Optional branch lab ID"),
) -> SuccessResponse[list[LabHolidayResponse]]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    holidays = await _service.list_holidays(db, lab_id=target_lab_id, from_date=from_date, to_date=to_date)
    return SuccessResponse(data=holidays)


@router.post(
    "/holidays",
    response_model=SuccessResponse[LabHolidayResponse],
    status_code=status.HTTP_201_CREATED,
    summary="Add a holiday, leave, or emergency closure",
    description="Registers a closure date range, deactivating appointment slots within this period.",
    dependencies=[Depends(require_permission(PermissionCode.LAB_WRITE))],
)
async def add_holiday(
    data: LabHolidayCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Optional branch lab ID"),
) -> SuccessResponse[LabHolidayResponse]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    holiday = await _service.add_holiday(db, data, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data=holiday, message="Holiday/closure scheduled successfully.")


@router.delete(
    "/holidays/{holiday_id}",
    response_model=SuccessResponse[dict[str, str]],
    status_code=status.HTTP_200_OK,
    summary="Delete a holiday or closure",
    dependencies=[Depends(require_permission(PermissionCode.LAB_WRITE))],
)
async def delete_holiday(
    holiday_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(get_current_user)],
    lab_id: UUID | None = Query(None, description="Optional branch lab ID"),
) -> SuccessResponse[dict[str, str]]:
    target_lab_id = await _resolve_lab_id(db, current_user, lab_id)
    await _service.delete_holiday(db, holiday_id, lab_id=target_lab_id, actor=current_user)
    return SuccessResponse(data={"id": str(holiday_id)}, message="Holiday removed successfully.")


@router.get(
    "/check-holiday",
    response_model=SuccessResponse[LabHolidayResponse | None],
    status_code=status.HTTP_200_OK,
    summary="Check if a specific calendar date is a holiday/closure",
)
async def check_holiday_for_date(
    target_date: Annotated[date, Query(alias="date", description="Target calendar date (YYYY-MM-DD)")],
    db: Annotated[AsyncSession, Depends(get_db)],
    lab_id: UUID | None = Query(None, description="Optional branch lab ID"),
) -> SuccessResponse[LabHolidayResponse | None]:
    holiday = await _service.check_holiday(db, target_date, lab_id=lab_id)
    return SuccessResponse(data=holiday)
