"""Dispatch validators — Phase 10.5."""
from __future__ import annotations

from shared.exceptions import AppError

from app.models.types import DispatchJobAction, DispatchJobStatus

ALLOWED_TRANSITIONS: dict[DispatchJobAction, set[DispatchJobStatus]] = {
    DispatchJobAction.ASSIGN: {DispatchJobStatus.PENDING},
    DispatchJobAction.START: {DispatchJobStatus.ASSIGNED},
    DispatchJobAction.COMPLETE: {
        DispatchJobStatus.ASSIGNED,
        DispatchJobStatus.IN_PROGRESS,
    },
    DispatchJobAction.CANCEL: {
        DispatchJobStatus.PENDING,
        DispatchJobStatus.ASSIGNED,
        DispatchJobStatus.IN_PROGRESS,
    },
    DispatchJobAction.FAIL: {
        DispatchJobStatus.PENDING,
        DispatchJobStatus.ASSIGNED,
        DispatchJobStatus.IN_PROGRESS,
    },
}

TARGET_STATUS: dict[DispatchJobAction, DispatchJobStatus] = {
    DispatchJobAction.ASSIGN: DispatchJobStatus.ASSIGNED,
    DispatchJobAction.START: DispatchJobStatus.IN_PROGRESS,
    DispatchJobAction.COMPLETE: DispatchJobStatus.COMPLETED,
    DispatchJobAction.CANCEL: DispatchJobStatus.CANCELLED,
    DispatchJobAction.FAIL: DispatchJobStatus.FAILED,
}

TERMINAL = frozenset(
    {DispatchJobStatus.COMPLETED, DispatchJobStatus.CANCELLED, DispatchJobStatus.FAILED}
)


def ensure_dispatch_job_transition(
    *, action: DispatchJobAction, current: DispatchJobStatus
) -> None:
    if current in TERMINAL:
        raise AppError(
            "کار ارسال در وضعیت پایانی است",
            status_code=409,
            error_code="dispatch_job_terminal",
            details={"status": current.value, "action": action.value},
        )
    allowed = ALLOWED_TRANSITIONS.get(action, set())
    if current not in allowed:
        raise AppError(
            "انتقال وضعیت کار ارسال مجاز نیست",
            status_code=409,
            error_code="invalid_dispatch_job_transition",
            details={
                "from_status": current.value,
                "action": action.value,
                "allowed_from": sorted(s.value for s in allowed),
            },
        )


def target_status_for(action: DispatchJobAction) -> DispatchJobStatus:
    return TARGET_STATUS[action]


def validate_dispatch_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
