"""Resolve structure capacity data for Ross1000 struttura blocks.

Reuses the same capacity calculation logic as C59 (available rooms/beds)
without importing from the C59 module — keeps the two pipelines independent.
"""

from __future__ import annotations

from django.db.models import ExpressionWrapper, F, IntegerField, Sum
from django.db.models.functions import Coalesce

from istat.ross1000.exceptions import Ross1000StructureError
from istat.ross1000.models.movement_payload import Ross1000StrutturaPayload
from properties.models import Property
from structures.models import Structure


def _available_rooms(structure: Structure) -> int:
    """Count available (sellable) rooms for the structure."""
    total = getattr(structure, "total_units", None) or getattr(structure, "total_rooms", None)
    if total and int(total) > 0:
        return int(total)
    return Property.objects.filter(
        structure=structure,
        availability=Property.Availability.AVAILABLE,
    ).count()


def _available_beds(structure: Structure) -> int:
    """Sum beds across all available properties (num_beds + num_sofa_beds)."""
    result = (
        Property.objects.filter(
            structure=structure,
            availability=Property.Availability.AVAILABLE,
        )
        .annotate(
            beds_per_room=ExpressionWrapper(
                Coalesce(F("property_type__num_beds"), 0)
                + Coalesce(F("property_type__num_sofa_beds"), 0),
                output_field=IntegerField(),
            )
        )
        .aggregate(total=Coalesce(Sum("beds_per_room"), 0))
    )
    return int(result["total"])


def build_struttura_payload(*, structure: Structure) -> Ross1000StrutturaPayload:
    """Build the base struttura payload for a structure.

    The camere_occupate field is set to 0 here — the movement builder
    overrides it per-day with the actual occupied count.

    Raises:
        Ross1000StructureError: If istat_code is missing.
    """
    istat_code = str(getattr(structure, "istat_code", "") or "").strip()
    if not istat_code:
        raise Ross1000StructureError(
            f"Structure {structure.id} is missing istat_code — "
            "cannot generate Ross1000 struttura block"
        )

    return Ross1000StrutturaPayload(
        codice=istat_code,
        apertura=1,
        camere_occupate=0,          # overridden per-day by movement_builder
        camere_disponibili=_available_rooms(structure),
        letti_disponibili=_available_beds(structure),
    )
