"""Template validators — Phase 11.4."""
from __future__ import annotations

from typing import Any

from app.models.types import (
    PageType,
    TemplateStatus,
    TemplateVersionStatus,
)
from app.validators.foundation import ValidationError, validate_non_empty
from shared.exceptions import AppError

TEMPLATE_STATUS_TRANSITIONS: dict[TemplateStatus, frozenset[TemplateStatus]] = {
    TemplateStatus.DRAFT: frozenset({TemplateStatus.ACTIVE, TemplateStatus.ARCHIVED}),
    TemplateStatus.ACTIVE: frozenset(
        {TemplateStatus.DEPRECATED, TemplateStatus.ARCHIVED}
    ),
    TemplateStatus.DEPRECATED: frozenset(
        {TemplateStatus.ACTIVE, TemplateStatus.ARCHIVED}
    ),
    TemplateStatus.ARCHIVED: frozenset(),
}

TEMPLATE_VERSION_STATUS_TRANSITIONS: dict[
    TemplateVersionStatus, frozenset[TemplateVersionStatus]
] = {
    TemplateVersionStatus.DRAFT: frozenset({TemplateVersionStatus.PUBLISHED}),
    TemplateVersionStatus.PUBLISHED: frozenset({TemplateVersionStatus.RETIRED}),
    TemplateVersionStatus.RETIRED: frozenset(),
}

_ALLOWED_PAGE_TYPES = {p.value for p in PageType}


def validate_page_type(page_type: str) -> str:
    page_type = validate_non_empty(page_type, "page_type").strip().lower()
    if page_type not in _ALLOWED_PAGE_TYPES:
        raise ValidationError(
            "page_type نامعتبر است",
            {"field": "page_type", "allowed": sorted(_ALLOWED_PAGE_TYPES)},
        )
    return page_type


def ensure_template_status_transition(
    current: TemplateStatus, target: TemplateStatus
) -> None:
    if current == target:
        return
    allowed = TEMPLATE_STATUS_TRANSITIONS.get(current, frozenset())
    if target not in allowed:
        raise AppError(
            "گذار وضعیت قالب مجاز نیست",
            error_code="invalid_template_status_transition",
            status_code=409,
            details={"current": current.value, "target": target.value},
        )


def ensure_template_version_status_transition(
    current: TemplateVersionStatus, target: TemplateVersionStatus
) -> None:
    if current == target:
        return
    allowed = TEMPLATE_VERSION_STATUS_TRANSITIONS.get(current, frozenset())
    if target not in allowed:
        raise AppError(
            "گذار وضعیت نسخه قالب مجاز نیست",
            error_code="invalid_template_version_status_transition",
            status_code=409,
            details={"current": current.value, "target": target.value},
        )


def ensure_template_version_mutable(version: Any) -> None:
    if getattr(version, "is_immutable", False) or getattr(
        version, "status", None
    ) == TemplateVersionStatus.PUBLISHED:
        raise AppError(
            "نسخه منتشرشده قالب قابل ویرایش نیست",
            error_code="template_version_immutable",
            status_code=409,
        )
    if getattr(version, "status", None) == TemplateVersionStatus.RETIRED:
        raise AppError(
            "نسخه بازنشسته‌شده قالب قابل ویرایش نیست",
            error_code="template_version_retired",
            status_code=409,
        )


def ensure_blueprint_json(payload: dict | None) -> dict | None:
    if payload is None:
        return None
    if not isinstance(payload, dict):
        raise ValidationError(
            "blueprint_json باید شیء JSON باشد", {"field": "blueprint_json"}
        )
    if "page_type" in payload and payload["page_type"] is not None:
        payload = {**payload, "page_type": validate_page_type(str(payload["page_type"]))}
    placements = payload.get("placement_shells")
    if placements is not None and not isinstance(placements, list):
        raise ValidationError(
            "placement_shells باید آرایه باشد",
            {"field": "blueprint_json.placement_shells"},
        )
    return payload
