"""Validation helpers for normalized ISTAT XML payload objects."""

from __future__ import annotations

from datetime import date

from istat.xml_export.exceptions import XmlPayloadValidationError
from istat.xml_export.payloads.guest_payload import IstatXmlGuestPayload
from istat.xml_export.services.lookup_service import IstatLookupService


def _is_blank(value: object) -> bool:
    if value is None:
        return True
    if isinstance(value, str):
        return not value.strip()
    return False


def require_value(value: object, field_name: str) -> None:
    """Raise an XML-specific validation error when a required value is missing."""
    if _is_blank(value):
        raise XmlPayloadValidationError(f"{field_name} is required for ISTAT XML payload")


def validate_stay_dates(arrival_date: date | None, departure_date: date | None) -> None:
    """Validate booking stay dates required by the XML payload."""
    require_value(arrival_date, "arrival_date")
    require_value(departure_date, "departure_date")

    if departure_date <= arrival_date:
        raise XmlPayloadValidationError(
            "departure_date must be after arrival_date for ISTAT XML payload"
        )


def validate_residence_payload(
    *,
    is_italian_resident: bool,
    residence_country_iso2: str | None,
    residence_country_code: str | None,
    province_sigla: str | None,
    province_code: str | None,
    region_code: str | None,
) -> None:
    """Validate mapped residence fields before building the guest payload."""
    require_value(residence_country_iso2, "country")

    if is_italian_resident:
        require_value(province_sigla, "province")
        require_value(province_code, "province_code")
        require_value(region_code, "region_code")

        if IstatLookupService.get_province(province_sigla) is None:
            raise XmlPayloadValidationError(
                f"Missing ISTAT province mapping for '{province_sigla}'"
            )
        if IstatLookupService.get_region_by_istat_code(region_code) is None:
            raise XmlPayloadValidationError(
                f"Missing ISTAT region mapping for '{region_code}'"
            )
        return

    require_value(residence_country_code, "residence_country_code")
    if IstatLookupService.get_country(residence_country_iso2) is None:
        raise XmlPayloadValidationError(
            f"Missing ISTAT country mapping for '{residence_country_iso2}'"
        )


def validate_payload(payload: IstatXmlGuestPayload) -> IstatXmlGuestPayload:
    """Validate a fully assembled XML guest payload and return it unchanged."""
    require_value(payload.booking_id, "booking_id")
    require_value(payload.guest_id, "guest_id")
    validate_stay_dates(payload.arrival_date, payload.departure_date)
    require_value(payload.guest_type, "guest_type")
    require_value(payload.gender, "gender")
    validate_residence_payload(
        is_italian_resident=payload.is_italian_resident,
        residence_country_iso2=payload.residence_country_iso2,
        residence_country_code=payload.residence_country_code,
        province_sigla=payload.province_sigla,
        province_code=payload.province_code,
        region_code=payload.region_code,
    )
    return payload

