"""Appointment validators — Phase 13.1."""
from __future__ import annotations

from datetime import datetime

from shared.exceptions import AppError

from app.models.types import AppointmentLifecycleAction, AppointmentStatus

ALLOWED_TRANSITIONS: dict[AppointmentLifecycleAction, set[AppointmentStatus]] = {
    AppointmentLifecycleAction.BOOK: set(),
    AppointmentLifecycleAction.CONFIRM: {AppointmentStatus.DRAFT},
    AppointmentLifecycleAction.CHECK_IN: {AppointmentStatus.CONFIRMED},
    AppointmentLifecycleAction.COMPLETE: {
        AppointmentStatus.CONFIRMED,
        AppointmentStatus.CHECKED_IN,
    },
    AppointmentLifecycleAction.CANCEL: {
        AppointmentStatus.DRAFT,
        AppointmentStatus.CONFIRMED,
        AppointmentStatus.CHECKED_IN,
    },
    AppointmentLifecycleAction.RESCHEDULE: {
        AppointmentStatus.DRAFT,
        AppointmentStatus.CONFIRMED,
    },
    AppointmentLifecycleAction.MARK_NO_SHOW: {AppointmentStatus.CONFIRMED},
}

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

TERMINAL_STATUSES = frozenset(
    {AppointmentStatus.COMPLETED, AppointmentStatus.CANCELLED, 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",
            details={"status": current.value, "action": action.value},
        )
    allowed = ALLOWED_TRANSITIONS.get(action, set())
    if action != AppointmentLifecycleAction.BOOK and current not in allowed:
        raise AppError(
            "انتقال وضعیت نوبت مجاز نیست",
            status_code=409,
            error_code="invalid_appointment_transition",
            details={
                "from_status": current.value,
                "action": action.value,
                "allowed_from": sorted(s.value for s in allowed),
            },
        )


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


def validate_time_window(*, starts_at: datetime, ends_at: datetime) -> None:
    if ends_at <= starts_at:
        raise AppError(
            "بازه زمانی نامعتبر است",
            status_code=422,
            error_code="invalid_time_window",
        )


def validate_schedule_times(*, start_time, end_time) -> None:
    if end_time <= start_time:
        raise AppError(
            "ساعت پایان باید بعد از ساعت شروع باشد",
            status_code=422,
            error_code="invalid_schedule_times",
        )
