"""Driver lifecycle validators — Phase 10.1."""
from __future__ import annotations

import re
from datetime import date

from shared.exceptions import AppError

from app.models.types import DriverLifecycleAction, DriverStatus
from app.validators.foundation import validate_non_empty

PHONE_RE = re.compile(r"^\+?[0-9]{8,15}$")
EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")

ALLOWED_TRANSITIONS: dict[DriverLifecycleAction, set[DriverStatus]] = {
    DriverLifecycleAction.ACTIVATE: {
        DriverStatus.PENDING,
        DriverStatus.INACTIVE,
        DriverStatus.SUSPENDED,
    },
    DriverLifecycleAction.SUSPEND: {DriverStatus.ACTIVE},
    DriverLifecycleAction.RESUME: {DriverStatus.SUSPENDED},
    DriverLifecycleAction.DEACTIVATE: {
        DriverStatus.ACTIVE,
        DriverStatus.SUSPENDED,
    },
    DriverLifecycleAction.BLOCK: {
        DriverStatus.PENDING,
        DriverStatus.ACTIVE,
        DriverStatus.SUSPENDED,
        DriverStatus.INACTIVE,
    },
    DriverLifecycleAction.UNBLOCK: {DriverStatus.BLOCKED},
    DriverLifecycleAction.ARCHIVE: {
        DriverStatus.INACTIVE,
        DriverStatus.BLOCKED,
    },
}

TERMINAL_STATUSES = frozenset({DriverStatus.ARCHIVED})

TARGET_STATUS: dict[DriverLifecycleAction, DriverStatus] = {
    DriverLifecycleAction.ACTIVATE: DriverStatus.ACTIVE,
    DriverLifecycleAction.SUSPEND: DriverStatus.SUSPENDED,
    DriverLifecycleAction.RESUME: DriverStatus.ACTIVE,
    DriverLifecycleAction.DEACTIVATE: DriverStatus.INACTIVE,
    DriverLifecycleAction.BLOCK: DriverStatus.BLOCKED,
    DriverLifecycleAction.UNBLOCK: DriverStatus.INACTIVE,
    DriverLifecycleAction.ARCHIVE: DriverStatus.ARCHIVED,
}


def ensure_driver_lifecycle_transition(
    *, action: DriverLifecycleAction, current: DriverStatus
) -> None:
    if current in TERMINAL_STATUSES:
        raise AppError(
            "راننده در وضعیت پایانی است و قابل تغییر نیست",
            status_code=409,
            error_code="driver_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_driver_lifecycle_transition",
            details={
                "from_status": current.value,
                "action": action.value,
                "allowed_from": sorted(s.value for s in allowed),
            },
        )


def target_status_for(action: DriverLifecycleAction) -> DriverStatus:
    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


def validate_mobile(mobile: str | None) -> str | None:
    if mobile is None or not str(mobile).strip():
        return None
    value = str(mobile).strip()
    if not PHONE_RE.match(value):
        raise AppError(
            "شماره موبایل نامعتبر است",
            status_code=422,
            error_code="invalid_mobile",
            details={"field": "mobile"},
        )
    return value


def validate_email(email: str | None) -> str | None:
    if email is None or not str(email).strip():
        return None
    value = str(email).strip()
    if not EMAIL_RE.match(value):
        raise AppError(
            "ایمیل نامعتبر است",
            status_code=422,
            error_code="invalid_email",
            details={"field": "email"},
        )
    return value


def validate_credential_dates(
    *, issued_at: date | None, expires_at: date | None
) -> None:
    if issued_at and expires_at and expires_at < issued_at:
        raise AppError(
            "تاریخ انقضا نمی‌تواند قبل از تاریخ صدور باشد",
            status_code=422,
            error_code="invalid_credential_dates",
        )


def validate_display_name(name: str) -> str:
    return validate_non_empty(name, "display_name")
