"""Tests for C59 aggregation builder.

Tests cover:
- Italian resident aggregation
- Foreign resident aggregation
- Multiple guests same residence aggregated correctly
- Different residences split correctly
- Province resolution
- Country resolution
- Missing province raises validation error
- Missing country mapping raises validation error
- Deterministic ordering
- Foreign guest ignores province
- residenza always 3 digits
"""

from datetime import date

from bookings.models import Booking
from django.test import TestCase
from guests.models import Guest
from istat.xml_export.builders.c59_aggregation_builder import (
    build_c59_aggregation_payloads,
    build_c59_aggregation_payloads_for_structure,
)
from istat.xml_export.exceptions import XmlPayloadValidationError
from istat.xml_export.models.c59_payload import IstatC59RowPayload
from istat.xml_export.services.c59_aggregation_service import (
    calculate_c59_available_beds,
    calculate_c59_available_rooms,
    calculate_c59_occupied_rooms,
)
from properties.models import Property, PropertyType
from structures.models import Structure


class C59AggregationTestCase(TestCase):
    """Test suite for C59 aggregation builder."""

    def setUp(self):
        """Create test structure and property."""
        from django.contrib.auth.models import User
        from properties.models import PropertyType
        self.user = User.objects.create_user(username="c59testuser", password="pass123")
        self.structure = Structure.objects.create(
            user=self.user,
            name="Test Structure",
            istat_code="TEST001",
        )
        self.property_type = PropertyType.objects.create(
            structure=self.structure,
            name="Standard Room",
            max_guests=4,
            num_beds=2,
        )
        self.property = Property.objects.create(
            name="Test Property",
            structure=self.structure,
            property_type=self.property_type,
        )

    def _create_booking_with_guests(self, check_in, check_out, guests_data):
        """Helper to create booking with guests.
        
        Args:
            check_in: Check-in date
            check_out: Check-out date
            guests_data: List of dicts with guest fields including:
                - full_name (required)
                - country (residence country, ISO-2)
                - extra_data (may contain province)
        """
        booking = Booking.objects.create(
            structure=self.structure,
            property=self.property,
            property_type=self.property_type,
            check_in_date=check_in,
            check_out_date=check_out,
            adults_count=len(guests_data),
            children_count=0,
            is_checked_in=True,
        )
        
        for guest_data in guests_data:
            Guest.objects.create(
                booking=booking,
                full_name=guest_data["full_name"],
                country=guest_data.get("country"),
                country_of_birth=guest_data.get("country_of_birth"),
                nationality=guest_data.get("nationality"),
                extra_data=guest_data.get("extra_data", {}),
                is_main_guest=(guest_data == guests_data[0]),
            )
        
        return booking

    def test_italian_resident_aggregation(self):
        """Test that Italian residents are aggregated with province code."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {
                    "full_name": "Mario Rossi",
                    "country": "IT",
                    "extra_data": {"province": "MI"},
                },
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 11),
        )
        
        # Should have one row for Italian resident from Milano
        self.assertEqual(len(payloads), 1)
        
        row = payloads[0]
        self.assertIsInstance(row, IstatC59RowPayload)
        self.assertEqual(row.nazione, "i")
        self.assertEqual(row.residenza, "015")  # MI = 015
        self.assertEqual(row.arrivi, 1)
        self.assertEqual(row.presenze, 1)
        self.assertEqual(row.partenze, 0)
        self.assertEqual(row.diurni, 0)

    def test_foreign_resident_aggregation(self):
        """Test that foreign residents are aggregated with country code."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {
                    "full_name": "John Smith",
                    "country": "US",
                },
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 11),
        )
        
        # Should have one row for US resident
        self.assertEqual(len(payloads), 1)
        
        row = payloads[0]
        self.assertEqual(row.nazione, "e")
        self.assertEqual(row.residenza, "400")  # US = 400
        self.assertEqual(row.arrivi, 1)
        self.assertEqual(row.presenze, 1)

    def test_residence_country_falls_back_to_birth_country(self):
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 11),
            guests_data=[
                {
                    "full_name": "Fallback Guest",
                    "country": None,
                    "nationality": None,
                    "country_of_birth": "IN",
                    "extra_data": {},
                },
            ],
        )

        Guest.objects.update(country=None, nationality=None)

        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 10),
        )

        self.assertEqual(len(payloads), 1)
        self.assertEqual(payloads[0].nazione, "e")
        self.assertEqual(payloads[0].residenza, "664")

    def test_multiple_guests_same_residence_aggregated(self):
        """Test that multiple guests from same residence are aggregated into ONE row."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 13),
            guests_data=[
                {
                    "full_name": "Guest 1",
                    "country": "IN",
                },
                {
                    "full_name": "Guest 2",
                    "country": "IN",
                },
                {
                    "full_name": "Guest 3",
                    "country": "IN",
                },
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 12),
        )
        
        # All 3 Indian guests should be ONE row
        self.assertEqual(len(payloads), 1)
        
        row = payloads[0]
        self.assertEqual(row.nazione, "e")
        self.assertEqual(row.residenza, "664")  # IN = 664
        self.assertEqual(row.arrivi, 3)
        self.assertEqual(row.presenze, 3)
        self.assertEqual(row.partenze, 0)

    def test_different_residences_split_correctly(self):
        """Test that different residences create separate rows."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {
                    "full_name": "Italian Guest",
                    "country": "IT",
                    "extra_data": {"province": "MI"},
                },
                {
                    "full_name": "US Guest",
                    "country": "US",
                },
                {
                    "full_name": "Another Italian",
                    "country": "IT",
                    "extra_data": {"province": "RM"},
                },
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 11),
        )
        
        # Should have 3 rows: MI, RM, US
        self.assertEqual(len(payloads), 3)
        
        # Verify sorted by (nazione, residenza)
        self.assertEqual(payloads[0].nazione, "e")
        self.assertEqual(payloads[0].residenza, "400")  # US
        
        self.assertEqual(payloads[1].nazione, "i")
        self.assertEqual(payloads[1].residenza, "015")  # MI
        
        self.assertEqual(payloads[2].nazione, "i")
        self.assertEqual(payloads[2].residenza, "058")  # RM

    def test_province_resolution_italian(self):
        """Test that Italian province codes are correctly resolved."""
        test_cases = [
            ("MI", "015"),  # Milano
            ("RM", "058"),  # Roma
            ("TO", "001"),  # Torino
            ("GE", "010"),  # Genova (Liguria)
            ("SV", "009"),  # Savona (Liguria)
        ]
        
        for province_sigla, expected_code in test_cases:
            with self.subTest(province=province_sigla):
                self._create_booking_with_guests(
                    check_in=date(2026, 1, 10),
                    check_out=date(2026, 1, 11),
                    guests_data=[
                        {
                            "full_name": f"Test {province_sigla}",
                            "country": "IT",
                            "extra_data": {"province": province_sigla},
                        },
                    ],
                )
                
                payloads = build_c59_aggregation_payloads(
                    Booking.objects.filter(structure=self.structure),
                    period_start=date(2026, 1, 10),
                    period_end=date(2026, 1, 10),
                )
                
                self.assertEqual(len(payloads), 1)
                self.assertEqual(payloads[0].residenza, expected_code)
                
                # Clean up for next iteration
                Booking.objects.filter(structure=self.structure).delete()

    def test_country_resolution_foreign(self):
        """Test that foreign country codes are correctly resolved."""
        test_cases = [
            ("US", "400"),  # United States
            ("IN", "664"),  # India
            ("GB", "006"),  # United Kingdom
            ("DE", "004"),  # Germany
            ("FR", "001"),  # France
        ]
        
        for country_iso, expected_code in test_cases:
            with self.subTest(country=country_iso):
                self._create_booking_with_guests(
                    check_in=date(2026, 1, 10),
                    check_out=date(2026, 1, 11),
                    guests_data=[
                        {
                            "full_name": f"Test {country_iso}",
                            "country": country_iso,
                        },
                    ],
                )
                
                payloads = build_c59_aggregation_payloads(
                    Booking.objects.filter(structure=self.structure),
                    period_start=date(2026, 1, 10),
                    period_end=date(2026, 1, 10),
                )
                
                self.assertEqual(len(payloads), 1)
                self.assertEqual(payloads[0].residenza, expected_code)
                
                # Clean up
                Booking.objects.filter(structure=self.structure).delete()

    def test_missing_province_raises_validation_error(self):
        """Test that Italian resident without province raises error."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 11),
            guests_data=[
                {
                    "full_name": "Italian No Province",
                    "country": "IT",
                    "extra_data": {},  # No province
                },
            ],
        )
        
        with self.assertRaises(XmlPayloadValidationError) as context:
            build_c59_aggregation_payloads(
                Booking.objects.filter(structure=self.structure),
                period_start=date(2026, 1, 10),
                period_end=date(2026, 1, 10),
            )
        
        self.assertIn("Province is required", str(context.exception))

    def test_missing_country_mapping_raises_validation_error(self):
        """Test that unknown country code raises error."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 11),
            guests_data=[
                {
                    "full_name": "Unknown Country",
                    "country": "XX",  # Invalid ISO code
                },
            ],
        )
        
        with self.assertRaises(XmlPayloadValidationError) as context:
            build_c59_aggregation_payloads(
                Booking.objects.filter(structure=self.structure),
                period_start=date(2026, 1, 10),
                period_end=date(2026, 1, 10),
            )
        
        self.assertIn("Missing ISTAT country mapping", str(context.exception))

    def test_deterministic_ordering(self):
        """Test that payloads are always sorted by (nazione, residenza)."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {"full_name": "Guest RM", "country": "IT", "extra_data": {"province": "RM"}},
                {"full_name": "Guest US", "country": "US"},
                {"full_name": "Guest MI", "country": "IT", "extra_data": {"province": "MI"}},
                {"full_name": "Guest IN", "country": "IN"},
                {"full_name": "Guest TO", "country": "IT", "extra_data": {"province": "TO"}},
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 11),
        )
        
        # Verify ordering: foreign first (sorted by code), then Italian (sorted by code)
        expected_order = [
            ("e", "400"),  # US
            ("e", "664"),  # IN
            ("i", "001"),  # TO
            ("i", "015"),  # MI
            ("i", "058"),  # RM
        ]
        
        self.assertEqual(len(payloads), len(expected_order))
        for i, (expected_nazione, expected_residenza) in enumerate(expected_order):
            self.assertEqual(payloads[i].nazione, expected_nazione)
            self.assertEqual(payloads[i].residenza, expected_residenza)

    def test_foreign_guest_ignores_province(self):
        """Test that province in extra_data is ignored for foreign guests."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 11),
            guests_data=[
                {
                    "full_name": "Foreign with Province",
                    "country": "US",
                    "extra_data": {"province": "MI"},  # Should be ignored
                },
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 10),
        )
        
        self.assertEqual(len(payloads), 1)
        self.assertEqual(payloads[0].nazione, "e")
        self.assertEqual(payloads[0].residenza, "400")  # US code, not MI code

    def test_residenza_always_3_digits(self):
        """Test that residenza is always exactly 3 digits."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {"full_name": "Guest MI", "country": "IT", "extra_data": {"province": "MI"}},
                {"full_name": "Guest US", "country": "US"},
                {"full_name": "Guest AO", "country": "IT", "extra_data": {"province": "AO"}},  # Aosta = 007
            ],
        )
        
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 11),
        )
        
        for payload in payloads:
            self.assertTrue(
                payload.residenza.isdigit(),
                f"residenza '{payload.residenza}' is not all digits"
            )
            self.assertEqual(
                len(payload.residenza),
                3,
                f"residenza '{payload.residenza}' is not 3 digits"
            )

    def test_arrivi_partenze_presenze_counts(self):
        """Test that arrival, departure, and presence counts are correct."""
        # Booking 1: Jan 10-12 (arrives 10th, present nights 10th & 11th)
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {"full_name": "Guest 1", "country": "IT", "extra_data": {"province": "MI"}},
            ],
        )
        
        # Booking 2: Jan 11-13 (arrives 11th, present 11th & 12th)
        self._create_booking_with_guests(
            check_in=date(2026, 1, 11),
            check_out=date(2026, 1, 13),
            guests_data=[
                {"full_name": "Guest 2", "country": "IT", "extra_data": {"province": "MI"}},
            ],
        )
        
        # Query for Jan 11 only
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 11),
            period_end=date(2026, 1, 11),
        )
        
        self.assertEqual(len(payloads), 1)
        row = payloads[0]
        
        # On Jan 11:
        # - Guest 1 is present (2nd night)
        # - Guest 2 is present (1st night) and arrives
        self.assertEqual(row.arrivi, 1)  # Guest 2 arrives
        self.assertEqual(row.partenze, 0)
        self.assertEqual(row.presenze, 2)  # Both guests present

    def test_departure_day_counts_partenze_without_presenze(self):
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {"full_name": "Guest 1", "country": "FR"},
                {"full_name": "Guest 2", "country": "FR"},
            ],
        )

        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 12),
            period_end=date(2026, 1, 12),
        )

        self.assertEqual(len(payloads), 1)
        self.assertEqual(payloads[0].nazione, "e")
        self.assertEqual(payloads[0].residenza, "001")
        self.assertEqual(payloads[0].arrivi, 0)
        self.assertEqual(payloads[0].partenze, 2)
        self.assertEqual(payloads[0].presenze, 0)

    def test_structure_wrapper(self):
        """Test the convenience wrapper for structure-based queries."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 12),
            guests_data=[
                {"full_name": "Guest", "country": "IT", "extra_data": {"province": "MI"}},
            ],
        )
        
        payloads = build_c59_aggregation_payloads_for_structure(
            structure_id=self.structure.id,
            start_date=date(2026, 1, 10),
            end_date=date(2026, 1, 11),
        )
        
        self.assertEqual(len(payloads), 1)
        self.assertEqual(payloads[0].nazione, "i")
        self.assertEqual(payloads[0].residenza, "015")

    def test_empty_bookings_returns_empty_list(self):
        """Test that no bookings returns empty payload list."""
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 11),
        )
        
        self.assertEqual(payloads, [])

    def test_capacity_and_occupied_room_counts_use_daily_overlap(self):
        self.property_type.num_beds = 2
        self.property_type.num_sofa_beds = 1
        self.property_type.save(update_fields=["num_beds", "num_sofa_beds"])
        self._make_booking(is_checked_in=True)

        self.assertEqual(calculate_c59_available_rooms(self.structure), 1)
        self.assertEqual(calculate_c59_available_beds(self.structure), 3)
        self.assertEqual(
            calculate_c59_occupied_rooms(
                structure_id=self.structure.id,
                target_date=date(2026, 5, 13),
            ),
            1,
        )
        self.assertEqual(
            calculate_c59_occupied_rooms(
                structure_id=self.structure.id,
                target_date=date(2026, 5, 14),
            ),
            0,
        )

    def test_multi_day_stay_counted_for_target_day_only(self):
        """Test that C59 aggregation is daily, not range-based."""
        self._create_booking_with_guests(
            check_in=date(2026, 1, 10),
            check_out=date(2026, 1, 15),  # 5 nights
            guests_data=[
                {"full_name": "Long Stay Guest", "country": "IT", "extra_data": {"province": "MI"}},
            ],
        )
        
        # Query for Jan 10-14 (5 nights)
        payloads = build_c59_aggregation_payloads(
            Booking.objects.filter(structure=self.structure),
            period_start=date(2026, 1, 10),
            period_end=date(2026, 1, 14),
        )
        
        self.assertEqual(len(payloads), 1)
        row = payloads[0]
        
        self.assertEqual(row.arrivi, 1)
        self.assertEqual(row.partenze, 0)
        self.assertEqual(row.presenze, 1)


class C59AggregationCheckedInFilterTests(TestCase):
    """Verify that build_c59_aggregation_payloads_for_structure only includes
    checked-in bookings, matching the ISTAT page dataset."""

    def setUp(self):
        from django.contrib.auth.models import User
        self.user = User.objects.create_user(username="c59filteruser", password="pass123")
        self.structure = Structure.objects.create(
            user=self.user,
            name="Filter Structure",
            istat_code="FLT002",
        )
        self.property_type = PropertyType.objects.create(
            structure=self.structure,
            name="Room",
            max_guests=2,
            num_beds=1,
        )
        self.property = Property.objects.create(
            name="Room A",
            structure=self.structure,
            property_type=self.property_type,
        )

    def _make_booking(self, *, is_checked_in, country="IT", province="MI"):
        booking = Booking.objects.create(
            structure=self.structure,
            property=self.property,
            property_type=self.property_type,
            check_in_date=date(2026, 5, 13),
            check_out_date=date(2026, 5, 14),
            adults_count=1,
            children_count=0,
            is_checked_in=is_checked_in,
        )
        Guest.objects.create(
            booking=booking,
            full_name="Test",
            is_main_guest=True,
            guest_type="16",
            gender="male",
            date_of_birth=date(1990, 1, 1),
            country_of_birth=country,
            nationality=country,
            country=country,
            extra_data={"province": province} if country == "IT" else {},
        )
        return booking

    def test_structure_wrapper_excludes_non_checked_in(self):
        """build_c59_aggregation_payloads_for_structure must exclude
        non-checked-in bookings."""
        self._make_booking(is_checked_in=True)   # included
        self._make_booking(is_checked_in=False)  # excluded

        payloads = build_c59_aggregation_payloads_for_structure(
            structure_id=self.structure.id,
            start_date=date(2026, 5, 13),
            end_date=date(2026, 5, 13),
        )

        # Only the checked-in booking contributes a row.
        self.assertEqual(len(payloads), 1)

    def test_structure_wrapper_non_checked_in_with_invalid_data_does_not_fail(self):
        """A non-checked-in booking with an unmappable country must not raise
        a validation error — it is simply excluded."""
        self._make_booking(is_checked_in=True)
        self._make_booking(is_checked_in=False, country="XX", province=None)

        # Must not raise.
        payloads = build_c59_aggregation_payloads_for_structure(
            structure_id=self.structure.id,
            start_date=date(2026, 5, 13),
            end_date=date(2026, 5, 13),
        )
        self.assertEqual(len(payloads), 1)

    def test_structure_wrapper_all_non_checked_in_returns_empty(self):
        """When all bookings are non-checked-in the wrapper returns an empty
        list."""
        self._make_booking(is_checked_in=False)

        payloads = build_c59_aggregation_payloads_for_structure(
            structure_id=self.structure.id,
            start_date=date(2026, 5, 13),
            end_date=date(2026, 5, 13),
        )
        self.assertEqual(payloads, [])


class C59AvailableBedsCalculationTests(TestCase):
    """Test suite for C59 available beds calculation with multiple property types."""

    def setUp(self):
        """Create test structure with multiple property types and properties."""
        from django.contrib.auth.models import User
        self.user = User.objects.create_user(username="bedscalcuser", password="pass123")
        self.structure = Structure.objects.create(
            user=self.user,
            name="Multi-Type Structure",
            istat_code="BED001",
        )

    def test_calculate_beds_single_property_type(self):
        """Test bed calculation with single property type."""
        property_type = PropertyType.objects.create(
            structure=self.structure,
            name="Standard",
            max_guests=2,
            num_beds=1,
            num_sofa_beds=0,
        )

        # Create 3 properties using this type
        for i in range(3):
            Property.objects.create(
                name=f"Room {i+1}",
                structure=self.structure,
                property_type=property_type,
                availability=Property.Availability.AVAILABLE,
            )

        beds = calculate_c59_available_beds(self.structure)
        # 3 properties × 1 bed each = 3 beds
        self.assertEqual(beds, 3)

    def test_calculate_beds_multiple_property_types(self):
        """Test bed calculation with multiple property types.
        
        Example from requirements:
        PropertyType A: num_beds = 2, rooms = 3 → 2×3 = 6
        PropertyType B: num_beds = 4, rooms = 2 → 4×2 = 8
        Expected total: 14
        """
        property_type_a = PropertyType.objects.create(
            structure=self.structure,
            name="Deluxe",
            max_guests=4,
            num_beds=2,
            num_sofa_beds=0,
        )

        property_type_b = PropertyType.objects.create(
            structure=self.structure,
            name="Suite",
            max_guests=6,
            num_beds=4,
            num_sofa_beds=0,
        )

        # Create 3 Deluxe properties
        for i in range(3):
            Property.objects.create(
                name=f"Deluxe {i+1}",
                structure=self.structure,
                property_type=property_type_a,
                availability=Property.Availability.AVAILABLE,
            )

        # Create 2 Suite properties
        for i in range(2):
            Property.objects.create(
                name=f"Suite {i+1}",
                structure=self.structure,
                property_type=property_type_b,
                availability=Property.Availability.AVAILABLE,
            )

        beds = calculate_c59_available_beds(self.structure)
        # (2 × 3) + (4 × 2) = 6 + 8 = 14
        self.assertEqual(beds, 14)

    def test_calculate_beds_with_sofa_beds(self):
        """Test that sofa beds are included in calculation."""
        property_type = PropertyType.objects.create(
            structure=self.structure,
            name="Room with Sofa",
            max_guests=3,
            num_beds=1,
            num_sofa_beds=2,
        )

        for i in range(2):
            Property.objects.create(
                name=f"Room {i+1}",
                structure=self.structure,
                property_type=property_type,
                availability=Property.Availability.AVAILABLE,
            )

        beds = calculate_c59_available_beds(self.structure)
        # 2 properties × (1 bed + 2 sofa_beds) = 2 × 3 = 6
        self.assertEqual(beds, 6)

    def test_calculate_beds_excludes_unavailable_properties(self):
        """Test that unavailable properties are not counted."""
        property_type = PropertyType.objects.create(
            structure=self.structure,
            name="Standard",
            max_guests=2,
            num_beds=1,
            num_sofa_beds=0,
        )

        # Create 2 available properties
        for i in range(2):
            Property.objects.create(
                name=f"Available {i+1}",
                structure=self.structure,
                property_type=property_type,
                availability=Property.Availability.AVAILABLE,
            )

        # Create 1 unavailable property
        Property.objects.create(
            name="Unavailable",
            structure=self.structure,
            property_type=property_type,
            availability=Property.Availability.UNDER_MAINTENANCE,
        )

        beds = calculate_c59_available_beds(self.structure)
        # Only 2 available properties × 1 bed = 2 beds
        self.assertEqual(beds, 2)

    def test_calculate_beds_zero_when_no_properties(self):
        """Test that zero beds returned when no available properties."""
        beds = calculate_c59_available_beds(self.structure)
        self.assertEqual(beds, 0)

    def test_calculate_beds_zero_beds_property_type(self):
        """Test handling of property type with zero beds."""
        property_type = PropertyType.objects.create(
            structure=self.structure,
            name="Activity Space",
            max_guests=0,
            num_beds=0,
            num_sofa_beds=0,
        )

        for i in range(2):
            Property.objects.create(
                name=f"Space {i+1}",
                structure=self.structure,
                property_type=property_type,
                availability=Property.Availability.AVAILABLE,
            )

        beds = calculate_c59_available_beds(self.structure)
        # 2 properties × 0 beds = 0
        self.assertEqual(beds, 0)

    def test_calculate_beds_mixed_zero_and_nonzero(self):
        """Test mixed scenario with some zero and non-zero property types."""
        property_type_zero = PropertyType.objects.create(
            structure=self.structure,
            name="Activity Space",
            max_guests=0,
            num_beds=0,
            num_sofa_beds=0,
        )

        property_type_beds = PropertyType.objects.create(
            structure=self.structure,
            name="Room",
            max_guests=2,
            num_beds=2,
            num_sofa_beds=0,
        )

        # 1 activity space with 0 beds
        Property.objects.create(
            name="Activity Space",
            structure=self.structure,
            property_type=property_type_zero,
            availability=Property.Availability.AVAILABLE,
        )

        # 2 rooms with 2 beds each
        for i in range(2):
            Property.objects.create(
                name=f"Room {i+1}",
                structure=self.structure,
                property_type=property_type_beds,
                availability=Property.Availability.AVAILABLE,
            )

        beds = calculate_c59_available_beds(self.structure)
        # (1 × 0) + (2 × 2) = 0 + 4 = 4
        self.assertEqual(beds, 4)

