"""Seat-map generation, shared by the operator API (configuring a bus's
layout) and the passenger website (rendering/booking against it).

Design choice that keeps every existing report/commission/manifest query
working untouched: Bus.total_seats is ALWAYS kept equal to the number of
BusSeat rows once a seat map exists. Every existing aggregate that reads
total_seats or Sum('seats_count') therefore stays correct with zero changes.
"""
from .models import Booking, BusSeat


def default_grid(total_seats):
    """A sensible rows x cols starting point for the operator to tweak."""
    if total_seats <= 12:
        cols = 3
    else:
        cols = 4
    rows = max(1, -(-total_seats // cols))  # ceil division
    return rows, cols


def seat_number_for(row, col, deck, deck_count):
    col_letter = chr(64 + col) if col <= 26 else str(col)
    prefix = '' if deck_count <= 1 else ('U' if deck == 2 else 'L')
    return f"{prefix}{row}{col_letter}"


def bus_has_active_bookings(bus):
    """True if any seat on this bus is tied to a non-cancelled booking -
    used to block destructive seat-map reconfiguration."""
    from .views import ACTIVE_BOOKING_STATES
    return Booking.objects.filter(
        schedule__bus=bus, booking_status__in=ACTIVE_BOOKING_STATES,
        booking_seats__isnull=False,
    ).exists()


def generate_seat_layout(bus, rows, cols, deck_count=1, seat_type_overrides=None):
    """(Re)generates every BusSeat row for a bus from a rows x cols x deck grid.
    Caller is responsible for checking bus_has_active_bookings() first."""
    seat_type_overrides = seat_type_overrides or {}
    valid_types = dict(BusSeat.SEAT_TYPE_CHOICES)

    BusSeat.objects.filter(bus=bus).delete()
    seats = []
    for deck in range(1, deck_count + 1):
        for row in range(1, rows + 1):
            for col in range(1, cols + 1):
                seat_number = seat_number_for(row, col, deck, deck_count)
                seat_type = seat_type_overrides.get(seat_number, 'STANDARD')
                if seat_type not in valid_types:
                    seat_type = 'STANDARD'
                seats.append(BusSeat(
                    bus=bus, deck=deck, row_number=row, col_number=col,
                    seat_number=seat_number, seat_type=seat_type,
                    is_active=(seat_type != 'BLOCKED'),
                ))
    BusSeat.objects.bulk_create(seats)

    bus.deck_count = deck_count
    bus.seat_rows = rows
    bus.seat_cols = cols
    bus.has_seat_map = True
    bus.total_seats = len(seats)  # keeps every existing aggregate query correct
    bus.save(update_fields=['deck_count', 'seat_rows', 'seat_cols', 'has_seat_map', 'total_seats'])
    return seats
