"""Member Management validators — Phase 9.2."""
from __future__ import annotations

from datetime import date

from shared.exceptions import AppError

from app.models.types import (
    CardKind,
    CardStatus,
    DocumentKind,
    FamilyRelationship,
    MemberStatus,
    MembershipStatus,
    WaiverStatus,
)
from app.validators.foundation import validate_non_empty


def validate_member_status(value: MemberStatus | str | None) -> MemberStatus:
    if value is None:
        return MemberStatus.ACTIVE
    try:
        return value if isinstance(value, MemberStatus) else MemberStatus(str(value))
    except ValueError as exc:
        raise AppError(
            "وضعیت عضو نامعتبر است",
            status_code=422,
            error_code="invalid_member_status",
        ) from exc


def validate_family_relationship(
    value: FamilyRelationship | str | None,
) -> FamilyRelationship:
    if value is None:
        return FamilyRelationship.OTHER
    try:
        return (
            value
            if isinstance(value, FamilyRelationship)
            else FamilyRelationship(str(value))
        )
    except ValueError as exc:
        raise AppError(
            "نسبت خانوادگی نامعتبر است",
            status_code=422,
            error_code="invalid_family_relationship",
        ) from exc


def validate_card_kind(value: CardKind | str | None) -> CardKind:
    if value is None:
        return CardKind.QR
    try:
        return value if isinstance(value, CardKind) else CardKind(str(value))
    except ValueError as exc:
        raise AppError(
            "نوع کارت نامعتبر است",
            status_code=422,
            error_code="invalid_card_kind",
        ) from exc


def validate_card_status(value: CardStatus | str | None) -> CardStatus:
    if value is None:
        return CardStatus.ACTIVE
    try:
        return value if isinstance(value, CardStatus) else CardStatus(str(value))
    except ValueError as exc:
        raise AppError(
            "وضعیت کارت نامعتبر است",
            status_code=422,
            error_code="invalid_card_status",
        ) from exc


def validate_waiver_status(value: WaiverStatus | str | None) -> WaiverStatus:
    if value is None:
        return WaiverStatus.PENDING
    try:
        return value if isinstance(value, WaiverStatus) else WaiverStatus(str(value))
    except ValueError as exc:
        raise AppError(
            "وضعیت تعهدنامه نامعتبر است",
            status_code=422,
            error_code="invalid_waiver_status",
        ) from exc


def validate_document_kind(value: DocumentKind | str | None) -> DocumentKind:
    if value is None:
        return DocumentKind.OTHER
    try:
        return value if isinstance(value, DocumentKind) else DocumentKind(str(value))
    except ValueError as exc:
        raise AppError(
            "نوع سند نامعتبر است",
            status_code=422,
            error_code="invalid_document_kind",
        ) from exc


def validate_file_ref(value: str | None, *, field: str = "file_ref") -> str:
    cleaned = validate_non_empty(value, field=field)
    if len(cleaned) > 255:
        raise AppError(
            f"{field} بیش از حد طولانی است",
            status_code=422,
            error_code="invalid_file_ref",
            details={"field": field},
        )
    return cleaned


def validate_freeze_window(
    freeze_starts_on: date | None, freeze_ends_on: date | None
) -> tuple[date | None, date | None]:
    if freeze_starts_on and freeze_ends_on and freeze_ends_on < freeze_starts_on:
        raise AppError(
            "بازه فریز نامعتبر است",
            status_code=422,
            error_code="invalid_freeze_window",
        )
    return freeze_starts_on, freeze_ends_on


def assert_membership_transition(
    current: MembershipStatus, target: MembershipStatus
) -> None:
    allowed: dict[MembershipStatus, set[MembershipStatus]] = {
        MembershipStatus.PENDING: {
            MembershipStatus.ACTIVE,
            MembershipStatus.CANCELLED,
            MembershipStatus.SUSPENDED,
        },
        MembershipStatus.ACTIVE: {
            MembershipStatus.FROZEN,
            MembershipStatus.SUSPENDED,
            MembershipStatus.EXPIRED,
            MembershipStatus.CANCELLED,
        },
        MembershipStatus.FROZEN: {
            MembershipStatus.ACTIVE,
            MembershipStatus.CANCELLED,
            MembershipStatus.EXPIRED,
        },
        MembershipStatus.SUSPENDED: {
            MembershipStatus.ACTIVE,
            MembershipStatus.CANCELLED,
            MembershipStatus.EXPIRED,
        },
        MembershipStatus.EXPIRED: {MembershipStatus.CANCELLED},
        MembershipStatus.CANCELLED: set(),
    }
    if target == current:
        return
    if target not in allowed.get(current, set()):
        raise AppError(
            "تغییر وضعیت عضویت مجاز نیست",
            status_code=422,
            error_code="invalid_membership_transition",
            details={"from": current.value, "to": target.value},
        )
