"""Appointment lifecycle validators — Phase 14.1."""
from __future__ import annotations

from shared.exceptions import AppError

from app.models.types import AppointmentLifecycleAction, AppointmentStatus

ALLOWED_TRANSITIONS: dict[AppointmentLifecycleAction, set[AppointmentStatus]] = {
    AppointmentLifecycleAction.CONFIRM: {AppointmentStatus.REQUESTED},
    AppointmentLifecycleAction.CHECK_IN: {AppointmentStatus.CONFIRMED},
    AppointmentLifecycleAction.START: {AppointmentStatus.CHECKED_IN},
    AppointmentLifecycleAction.COMPLETE: {AppointmentStatus.IN_PROGRESS, AppointmentStatus.CHECKED_IN},
    AppointmentLifecycleAction.CANCEL: {
        AppointmentStatus.REQUESTED,
        AppointmentStatus.CONFIRMED,
        AppointmentStatus.CHECKED_IN,
    },
    AppointmentLifecycleAction.NO_SHOW: {AppointmentStatus.CONFIRMED},
}

TERMINAL_STATUSES = frozenset(
    {AppointmentStatus.COMPLETED, AppointmentStatus.CANCELLED, AppointmentStatus.NO_SHOW}
)

TARGET_STATUS: dict[AppointmentLifecycleAction, AppointmentStatus] = {
    AppointmentLifecycleAction.CONFIRM: AppointmentStatus.CONFIRMED,
    AppointmentLifecycleAction.CHECK_IN: AppointmentStatus.CHECKED_IN,
    AppointmentLifecycleAction.START: AppointmentStatus.IN_PROGRESS,
    AppointmentLifecycleAction.COMPLETE: AppointmentStatus.COMPLETED,
    AppointmentLifecycleAction.CANCEL: AppointmentStatus.CANCELLED,
    AppointmentLifecycleAction.NO_SHOW: AppointmentStatus.NO_SHOW,
}


def ensure_appointment_lifecycle_transition(
    *, action: AppointmentLifecycleAction, current: AppointmentStatus
) -> None:
    if current in TERMINAL_STATUSES:
        raise AppError(
            "نوبت در وضعیت پایانی است",
            status_code=409,
            error_code="appointment_terminal",
        )
    allowed = ALLOWED_TRANSITIONS.get(action, set())
    if current not in allowed:
        raise AppError(
            "انتقال وضعیت نوبت مجاز نیست",
            status_code=409,
            error_code="invalid_appointment_lifecycle_transition",
        )


def target_status_for(action: AppointmentLifecycleAction) -> AppointmentStatus:
    return TARGET_STATUS[action]


def validate_reason(reason: str | None, *, required: bool = False) -> str | None:
    if reason is None or not str(reason).strip():
        if required:
            raise AppError("دلیل الزامی است", status_code=422, error_code="reason_required")
        return None
    text = str(reason).strip()
    if len(text) > 500:
        raise AppError("دلیل بیش از حد طولانی است", status_code=422, error_code="reason_too_long")
    return text
