"""Scheduling router — service events (prefix: /services)."""
from datetime import date
from typing import Optional
from uuid import UUID

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

from src.core.constants import UserRole
from src.core.dependencies import require_min_role, require_tenant
from src.core.schemas.response import paginated, success
from src.database.session import get_db
from src.apps.auth.models.user import User
from src.apps.scheduling.models.service_event import ServiceEvent
from src.apps.scheduling.schemas.requests import ServiceCreate, ServiceUpdate, ExportWeekPdfRequest
from src.apps.scheduling.schemas.responses import (
    ServiceDetail,
    ServiceListItem,
    StaffAssignmentItem,
    WeekSummaryItem,
)
from src.apps.scheduling.services.service_service import ServiceService

router = APIRouter(prefix="/services", tags=["scheduling"])

_svc = ServiceService()


# ── Helpers ───────────────────────────────────────────────────────────────────


def _serialize_event(event: ServiceEvent, assignments=None) -> dict:
    """Serialize a ServiceEvent ORM object to a plain dict for the response."""
    detail = ServiceDetail.model_validate(event)
    data = detail.model_dump()

    # Replace staff_assignments from the ORM field with provided list (if any)
    if assignments is not None:
        data["staff_assignments"] = [
            StaffAssignmentItem.model_validate(a).model_dump() for a in assignments
        ]

    # Ensure date/time fields are ISO strings (Pydantic already handles this via model_dump)
    return data


# ── Week calendar ─────────────────────────────────────────────────────────────


@router.get("/week")
async def get_week(
    week_start: date = Query(..., description="ISO date — first day of the week"),
    event_type: Optional[str] = Query(None, description="Filter by service type"),
    current_user: User = Depends(require_min_role(UserRole.STAFF)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Return all services in a 7-day window, grouped for the calendar view."""
    events = await _svc.get_week(db, tenant_id, week_start, event_type)

    items = []
    for event in events:
        assignments = await _svc.get_assignments(db, event.id)
        item = WeekSummaryItem(
            id=event.id,
            service_type=event.service_type,
            scheduled_date=event.scheduled_date,
            scheduled_time=event.scheduled_time,
            family_contact_name=event.family_contact_name,
            plot_id=event.plot_id,
            officiant=event.officiant,
            status=event.status,
            crew_names=[],  # TODO: join user names when user table is eager-loaded
        )
        items.append(item.model_dump())

    return success(items, f"{len(items)} services in week")


# ── Summary table (paginated) ─────────────────────────────────────────────────


@router.get("/summary")
async def get_summary(
    week_start: date = Query(..., description="ISO date — first day of the week"),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    current_user: User = Depends(require_min_role(UserRole.STAFF)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Return a paginated summary table for the given week."""
    events, total = await _svc.get_summary_table(db, tenant_id, week_start, page, page_size)
    items = [ServiceListItem.model_validate(e).model_dump() for e in events]
    return paginated(items, total, page, page_size)


# ── Create ────────────────────────────────────────────────────────────────────


@router.post("", status_code=201)
async def create_service(
    body: ServiceCreate,
    current_user: User = Depends(require_min_role(UserRole.STAFF)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Create a new service event with optional crew assignments."""
    event = await _svc.create(db, tenant_id, body, current_user)
    assignments = await _svc.get_assignments(db, event.id)
    return success(_serialize_event(event, assignments), "Service created")


# ── Get by ID ─────────────────────────────────────────────────────────────────


@router.get("/{service_id}")
async def get_service(
    service_id: UUID,
    current_user: User = Depends(require_min_role(UserRole.STAFF)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Return a single service event."""
    event = await _svc.get_by_id(db, tenant_id, service_id)
    assignments = await _svc.get_assignments(db, event.id)
    return success(_serialize_event(event, assignments))


# ── Update ────────────────────────────────────────────────────────────────────


@router.put("/{service_id}")
async def update_service(
    service_id: UUID,
    body: ServiceUpdate,
    current_user: User = Depends(require_min_role(UserRole.STAFF)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Update a service event. Passing assigned_crew_ids replaces all assignments."""
    event = await _svc.update(db, tenant_id, service_id, body, current_user)
    assignments = await _svc.get_assignments(db, event.id)
    return success(_serialize_event(event, assignments), "Service updated")


# ── Soft delete ───────────────────────────────────────────────────────────────


@router.delete("/{service_id}", status_code=204)
async def delete_service(
    service_id: UUID,
    current_user: User = Depends(require_min_role(UserRole.MANAGER)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Soft-delete a service event (MANAGER or above required)."""
    await _svc.soft_delete(db, tenant_id, service_id, current_user)


# ── Export week PDF (enqueue ARQ job) ─────────────────────────────────────────


@router.post("/export-week-pdf")
async def export_week_pdf(
    body: ExportWeekPdfRequest,
    current_user: User = Depends(require_min_role(UserRole.STAFF)),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Enqueue an ARQ job to generate the weekly run-sheet PDF and return the job ID."""
    try:
        from arq.connections import RedisSettings, create_pool
        from src.core.config import settings as app_settings

        redis = await create_pool(RedisSettings.from_dsn(app_settings.REDIS_URL))
        job = await redis.enqueue_job(
            "export_week_pdf",
            tenant_id=str(tenant_id),
            week_start=body.week_start.isoformat(),
        )
        await redis.close()
        job_id = str(job.job_id) if job else None
    except Exception:
        job_id = None

    return success({"job_id": job_id}, "PDF export queued")
