"""
Resos API Endpoints

Handles Resos configuration, sync operations, and booking data retrieval.
"""
import logging
from datetime import date, datetime, timedelta
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, func, Date, case, or_
from pydantic import BaseModel

logger = logging.getLogger(__name__)

from database import get_db
from models.user import User
from models.settings import KitchenSettings
from models.resos import ResosBooking, ResosDailyStats, ResosOpeningHour, ResosSyncLog
from auth import get_current_user, require_cap
from services.resos_sync import ResosSyncService
from services.resos_api import ResosAPIClient, ResosAPIError

router = APIRouter()


# ============ Pydantic Schemas ============

class ResosSettingsResponse(BaseModel):
    resos_api_key_set: bool  # Masked
    resos_last_sync: datetime | None
    resos_auto_sync_enabled: bool
    resos_upcoming_sync_enabled: bool
    resos_upcoming_sync_interval: int
    resos_last_upcoming_sync: datetime | None
    resos_large_group_threshold: int
    resos_note_keywords: str | None
    resos_allergy_keywords: str | None
    resos_custom_field_mapping: dict | None
    resos_opening_hours_mapping: list | None
    resos_restaurant_table_entities: str | None
    resos_enable_manual_breakfast: bool
    resos_manual_breakfast_periods: list | None
    resos_flag_icon_mapping: dict | None
    resos_arrival_widget_service_filter: str | None  # Service type: breakfast/lunch/dinner/other
    sambapos_food_gl_codes: str | None  # Phase 8.1
    sambapos_beverage_gl_codes: str | None  # Phase 8.1

    class Config:
        from_attributes = True


class ResosSettingsUpdate(BaseModel):
    resos_api_key: str | None = None
    resos_auto_sync_enabled: bool | None = None
    resos_upcoming_sync_enabled: bool | None = None
    resos_upcoming_sync_interval: int | None = None
    resos_large_group_threshold: int | None = None
    resos_note_keywords: str | None = None
    resos_allergy_keywords: str | None = None
    resos_custom_field_mapping: dict | None = None
    resos_opening_hours_mapping: list | None = None
    resos_restaurant_table_entities: str | None = None
    resos_enable_manual_breakfast: bool | None = None
    resos_manual_breakfast_periods: list | None = None
    resos_flag_icon_mapping: dict | None = None
    resos_arrival_widget_service_filter: str | None = None  # Opening hour ID for arrivals widget filter
    sambapos_food_gl_codes: str | None = None  # Phase 8.1
    sambapos_beverage_gl_codes: str | None = None  # Phase 8.1


class DailyStatsResponse(BaseModel):
    date: str
    total_bookings: int
    total_covers: int
    service_breakdown: list[dict]
    flagged_booking_count: int
    unique_flag_types: list[str] | None
    is_forecast: bool

    class Config:
        from_attributes = True


class BookingResponse(BaseModel):
    id: int
    resos_booking_id: str
    booking_date: str
    booking_time: str
    people: int
    status: str
    seating_area: str | None
    hotel_booking_number: str | None
    is_hotel_guest: bool | None
    is_dbb: bool | None
    is_package: bool | None
    allergies: str | None
    notes: str | None
    opening_hour_name: str | None
    is_flagged: bool
    flag_reasons: str | None

    class Config:
        from_attributes = True


class DashboardCoversResponse(BaseModel):
    date: str
    total_bookings: int
    total_covers: int
    service_breakdown: list[dict]
    has_flagged_bookings: bool
    unique_flag_types: list[str]

    class Config:
        from_attributes = True


# ============ Settings Endpoints ============

@router.get("/settings")
async def get_resos_settings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> ResosSettingsResponse:
    """Get Resos settings"""
    result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = result.scalar_one()

    logger.info(f"[Resos GET] Returning upcoming_sync_enabled={settings.resos_upcoming_sync_enabled}")

    return ResosSettingsResponse(
        resos_api_key_set=bool(settings.resos_api_key),
        resos_last_sync=settings.resos_last_sync,
        resos_auto_sync_enabled=settings.resos_auto_sync_enabled or False,
        resos_upcoming_sync_enabled=settings.resos_upcoming_sync_enabled or False,
        resos_upcoming_sync_interval=settings.resos_upcoming_sync_interval or 15,
        resos_last_upcoming_sync=settings.resos_last_upcoming_sync,
        resos_large_group_threshold=settings.resos_large_group_threshold or 8,
        resos_note_keywords=settings.resos_note_keywords,
        resos_allergy_keywords=settings.resos_allergy_keywords,
        resos_custom_field_mapping=settings.resos_custom_field_mapping,
        resos_opening_hours_mapping=settings.resos_opening_hours_mapping,
        resos_restaurant_table_entities=settings.resos_restaurant_table_entities,
        resos_enable_manual_breakfast=settings.resos_enable_manual_breakfast or False,
        resos_manual_breakfast_periods=settings.resos_manual_breakfast_periods,
        resos_flag_icon_mapping=settings.resos_flag_icon_mapping,
        resos_arrival_widget_service_filter=settings.resos_arrival_widget_service_filter,
        sambapos_food_gl_codes=settings.sambapos_food_gl_codes,  # Phase 8.1
        sambapos_beverage_gl_codes=settings.sambapos_beverage_gl_codes  # Phase 8.1
    )


@router.patch("/settings")
async def update_resos_settings(
    update: ResosSettingsUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Update Resos settings"""
    logger.info(f"[Resos PATCH] Received update: {update.model_dump(exclude_unset=True)}")

    result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = result.scalar_one()

    logger.info(f"[Resos PATCH] Before update - upcoming_sync_enabled={settings.resos_upcoming_sync_enabled}")

    if update.resos_api_key is not None:
        settings.resos_api_key = update.resos_api_key
    if update.resos_auto_sync_enabled is not None:
        settings.resos_auto_sync_enabled = update.resos_auto_sync_enabled
    if update.resos_upcoming_sync_enabled is not None:
        logger.info(f"[Resos PATCH] Setting upcoming_sync_enabled to {update.resos_upcoming_sync_enabled}")
        settings.resos_upcoming_sync_enabled = update.resos_upcoming_sync_enabled
    if update.resos_upcoming_sync_interval is not None:
        settings.resos_upcoming_sync_interval = update.resos_upcoming_sync_interval
    if update.resos_large_group_threshold is not None:
        settings.resos_large_group_threshold = update.resos_large_group_threshold
    if update.resos_note_keywords is not None:
        settings.resos_note_keywords = update.resos_note_keywords
    if update.resos_allergy_keywords is not None:
        settings.resos_allergy_keywords = update.resos_allergy_keywords
    if update.resos_custom_field_mapping is not None:
        settings.resos_custom_field_mapping = update.resos_custom_field_mapping
    if update.resos_opening_hours_mapping is not None:
        settings.resos_opening_hours_mapping = update.resos_opening_hours_mapping
    if update.resos_restaurant_table_entities is not None:
        settings.resos_restaurant_table_entities = update.resos_restaurant_table_entities
    if update.resos_enable_manual_breakfast is not None:
        settings.resos_enable_manual_breakfast = update.resos_enable_manual_breakfast
    if update.resos_manual_breakfast_periods is not None:
        settings.resos_manual_breakfast_periods = update.resos_manual_breakfast_periods
    if update.resos_flag_icon_mapping is not None:
        settings.resos_flag_icon_mapping = update.resos_flag_icon_mapping
    if update.resos_arrival_widget_service_filter is not None:
        settings.resos_arrival_widget_service_filter = update.resos_arrival_widget_service_filter
    # Phase 8.1: GL codes for food/beverage spend split
    if update.sambapos_food_gl_codes is not None:
        settings.sambapos_food_gl_codes = update.sambapos_food_gl_codes
    if update.sambapos_beverage_gl_codes is not None:
        settings.sambapos_beverage_gl_codes = update.sambapos_beverage_gl_codes

    await db.commit()
    logger.info(f"[Resos PATCH] After commit - upcoming_sync_enabled={settings.resos_upcoming_sync_enabled}")
    return {"message": "Settings updated successfully"}


@router.post("/test-connection")
async def test_resos_connection(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Test Resos API connection"""
    result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = result.scalar_one()

    if not settings.resos_api_key:
        raise HTTPException(status_code=400, detail="Resos API key not configured")

    async with ResosAPIClient(settings.resos_api_key) as client:
        success = await client.test_connection()

    if not success:
        raise HTTPException(status_code=400, detail="Connection failed")

    return {"message": "Connection successful"}


@router.get("/debug-upcoming-sync")
async def debug_upcoming_sync(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Debug endpoint to check upcoming sync settings directly"""
    from sqlalchemy import text

    # Get value via ORM
    result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = result.scalar_one()
    orm_value = settings.resos_upcoming_sync_enabled

    # Get value via raw SQL
    raw_result = await db.execute(
        text("SELECT resos_upcoming_sync_enabled, resos_upcoming_sync_interval FROM kitchen_settings WHERE kitchen_id = :kid"),
        {"kid": current_user.kitchen_id}
    )
    raw_row = raw_result.fetchone()

    return {
        "orm_value": orm_value,
        "raw_db_enabled": raw_row[0] if raw_row else None,
        "raw_db_interval": raw_row[1] if raw_row else None,
        "column_exists": raw_row is not None
    }


@router.get("/custom-fields")
async def fetch_custom_fields(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Fetch custom field definitions from Resos API (GET request only)"""
    result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = result.scalar_one()

    if not settings.resos_api_key:
        raise HTTPException(status_code=400, detail="Resos API key not configured")

    async with ResosAPIClient(settings.resos_api_key) as client:
        fields = await client.get_custom_field_definitions()

    return {"custom_fields": fields}


@router.get("/opening-hours")
async def fetch_opening_hours(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Fetch opening hours/service periods from Resos API (GET request only)"""
    import logging
    logger = logging.getLogger(__name__)

    result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = result.scalar_one()

    if not settings.resos_api_key:
        raise HTTPException(status_code=400, detail="Resos API key not configured")

    async with ResosAPIClient(settings.resos_api_key) as client:
        hours = await client.get_opening_hours()

    # Log the raw response to understand structure
    logger.info(f"Raw opening hours from Resos API: {len(hours)} periods")

    # Filter out special/one-off periods - only return regular service periods
    # Filter on 'special' field: True = one-off events, False = recurring service periods
    regular_hours = [h for h in hours if h.get('special') == False]

    # Day of week mapping (Resos uses 1=Monday, 7=Sunday)
    day_names = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

    # Transform time format: Resos uses 'open' and 'close' as HHMM integers (e.g., 1200 = 12:00)
    # Convert to 'startTime' and 'endTime' in HH:MM format for frontend
    for hour in regular_hours:
        # Add day of week name
        day_num = hour.get('day', 0)
        if 1 <= day_num <= 7:
            hour['dayName'] = day_names[day_num]
        else:
            hour['dayName'] = 'Unknown'

        if 'open' in hour:
            open_val = hour['open']
            hours_part = open_val // 100
            mins_part = open_val % 100
            hour['startTime'] = f"{hours_part:02d}:{mins_part:02d}"

        if 'close' in hour:
            close_val = hour['close']
            hours_part = close_val // 100
            mins_part = close_val % 100
            hour['endTime'] = f"{hours_part:02d}:{mins_part:02d}"

            # Auto-calculate actual end time by subtracting booking duration
            # Resos extends close time to allow late bookings
            seating = hour.get('seating', {})
            duration = seating.get('duration', 0)  # Duration in minutes
            if duration > 0:
                # Convert close time to minutes
                close_minutes = hours_part * 60 + mins_part
                # Subtract booking duration
                actual_end_minutes = close_minutes - duration
                # Convert back to HH:MM
                actual_hours = actual_end_minutes // 60
                actual_mins = actual_end_minutes % 60
                hour['actualEnd'] = f"{actual_hours:02d}:{actual_mins:02d}"
                hour['bookingDuration'] = duration

    # Sort by day of week first, then by open time within each day
    regular_hours.sort(key=lambda h: (h.get('day', 0), h.get('open', 0)))

    logger.info(f"After filtering: {len(regular_hours)} regular periods (filtered out {len(hours) - len(regular_hours)} special periods)")

    return {"opening_hours": regular_hours}


@router.get("/opening-hours/{date}")
async def get_opening_hours_for_date(
    date: str,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Get opening hours configuration for a specific date

    Returns opening hour periods with their times and intervals.
    Used by Gantt chart to determine time range and closed periods.
    """
    import logging
    logger = logging.getLogger(__name__)

    # Parse date
    try:
        query_date = datetime.fromisoformat(date).date()
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid date format")

    # Get kitchen settings
    settings_result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = settings_result.scalar_one_or_none()

    if not settings or not settings.resos_api_key:
        logger.warning("No Resos API key configured")
        return []

    # Fetch opening hours from Resos API
    async with ResosAPIClient(settings.resos_api_key) as client:
        hours = await client.get_opening_hours()

    # Filter to regular (non-special) hours and format for Gantt chart
    day_of_week = query_date.isoweekday()  # Monday=1, Sunday=7

    formatted_hours = []
    for hour in hours:
        # Skip special/one-off periods
        if hour.get('special') == True:
            continue

        # Check if this opening hour applies to the query date's day of week
        hour_day = hour.get('day', 0)
        if hour_day != day_of_week:
            continue

        # Get open and close times (already in HHMM format from API)
        open_time = hour.get('open', 0)
        close_time = hour.get('close', 0)

        # Find service type from mapping
        resos_id = hour.get('id', '')
        service_type = None
        if settings.resos_opening_hours_mapping:
            for mapping in settings.resos_opening_hours_mapping:
                if isinstance(mapping, dict) and mapping.get('resos_id') == resos_id:
                    service_type = mapping.get('service_type', '')
                    break

        formatted_hours.append({
            "name": hour.get('name', ''),
            "service_type": service_type or hour.get('name', ''),
            "open": open_time,
            "close": close_time,
            "is_special": False
        })

    logger.info(f"Found {len(formatted_hours)} opening hours for {query_date} (day {day_of_week})")
    return formatted_hours


# ============ Sync Endpoints ============

@router.post("/sync/upcoming")
async def sync_upcoming(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Manual upcoming sync (next 7 days) - triggers immediately and updates last_upcoming_sync timestamp"""
    sync_service = ResosSyncService(current_user.kitchen_id, db)
    result = await sync_service.run_upcoming_sync()
    logger.info(f"[Resos] Manual upcoming sync completed for kitchen {current_user.kitchen_id}")
    return result


@router.post("/sync/forecast")
async def sync_forecast(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Manual forecast sync (next 60 days)"""
    sync_service = ResosSyncService(current_user.kitchen_id, db)

    today = date.today()
    to_date = today + timedelta(days=60)

    result = await sync_service.sync_bookings(today, to_date, is_forecast=True)
    return result


@router.post("/sync/historical")
async def sync_historical(
    from_date: date,
    to_date: date,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Manual historical sync"""
    sync_service = ResosSyncService(current_user.kitchen_id, db)
    result = await sync_service.sync_bookings(from_date, to_date, is_forecast=False)
    return result


@router.post("/sync/opening-hours")
async def sync_opening_hours(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Sync opening hours from Resos API to local database"""
    import logging
    logger = logging.getLogger(__name__)

    logger.info(f"Starting opening hours sync for kitchen {current_user.kitchen_id}")

    sync_service = ResosSyncService(current_user.kitchen_id, db)
    count = await sync_service.sync_opening_hours()

    logger.info(f"Successfully synced {count} opening hours to database")

    return {
        "message": f"Successfully synced {count} opening hours",
        "count": count
    }


# ============ Data Retrieval Endpoints ============

@router.get("/daily-stats")
async def get_daily_stats(
    from_date: date,
    to_date: date,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> list[DailyStatsResponse]:
    """Get daily stats for date range"""
    result = await db.execute(
        select(ResosDailyStats).where(
            and_(
                ResosDailyStats.kitchen_id == current_user.kitchen_id,
                ResosDailyStats.date >= from_date,
                ResosDailyStats.date <= to_date
            )
        ).order_by(ResosDailyStats.date)
    )

    stats = result.scalars().all()

    return [
        DailyStatsResponse(
            date=stat.date.isoformat(),
            total_bookings=stat.total_bookings,
            total_covers=stat.total_covers,
            service_breakdown=stat.service_breakdown or [],
            flagged_booking_count=stat.flagged_booking_count,
            unique_flag_types=stat.unique_flag_types,
            is_forecast=stat.is_forecast
        )
        for stat in stats
    ]


@router.get("/bookings/{booking_date}")
async def get_bookings_for_date(
    booking_date: date,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> list[BookingResponse]:
    """Get all bookings for a specific date, excluding cancelled/deleted"""
    excluded_statuses = ['canceled', 'cancelled', 'waitlist', 'deleted', 'declined', 'rejected']
    result = await db.execute(
        select(ResosBooking).where(
            and_(
                ResosBooking.kitchen_id == current_user.kitchen_id,
                ResosBooking.booking_date == booking_date,
                ~func.lower(ResosBooking.status).in_(excluded_statuses)
            )
        ).order_by(ResosBooking.booking_time)
    )

    bookings = result.scalars().all()

    return [
        BookingResponse(
            id=b.id,
            resos_booking_id=b.resos_booking_id,
            booking_date=b.booking_date.isoformat(),
            booking_time=b.booking_time.isoformat(),
            people=b.people,
            status=b.status,
            seating_area=b.seating_area,
            hotel_booking_number=b.hotel_booking_number,
            is_hotel_guest=b.is_hotel_guest,
            is_dbb=b.is_dbb,
            is_package=b.is_package,
            allergies=b.allergies,
            notes=b.notes,
            opening_hour_name=b.opening_hour_name,
            is_flagged=b.is_flagged,
            flag_reasons=b.flag_reasons
        )
        for b in bookings
    ]


# ============ Dashboard Endpoint ============

@router.get("/dashboard/today-tomorrow")
async def get_dashboard_covers(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> dict:
    """Get today, tomorrow, and day after tomorrow covers for dashboard"""
    import logging
    logger = logging.getLogger(__name__)

    today = date.today()
    tomorrow = today + timedelta(days=1)
    day_after = today + timedelta(days=2)

    # Day names for display
    day_names = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

    result = await db.execute(
        select(ResosDailyStats).where(
            and_(
                ResosDailyStats.kitchen_id == current_user.kitchen_id,
                ResosDailyStats.date.in_([today, tomorrow, day_after])
            )
        )
    )

    stats = {stat.date: stat for stat in result.scalars().all()}

    def build_response(target_date: date, day_label: str) -> Optional[dict]:
        if target_date not in stats:
            return {
                'date': target_date.isoformat(),
                'day_label': day_label,
                'total_bookings': 0,
                'total_covers': 0,
                'service_breakdown': [],
                'has_flagged_bookings': False,
                'unique_flag_types': []
            }
        stat = stats[target_date]
        logger.info(f"Date {target_date}: unique_flag_types={stat.unique_flag_types}, type={type(stat.unique_flag_types)}, flagged_count={stat.flagged_booking_count}")
        return {
            'date': stat.date.isoformat(),
            'day_label': day_label,
            'total_bookings': stat.total_bookings,
            'total_covers': stat.total_covers,
            'service_breakdown': stat.service_breakdown or [],
            'has_flagged_bookings': stat.flagged_booking_count > 0,
            'unique_flag_types': stat.unique_flag_types or []
        }

    return {
        'today': build_response(today, 'Today'),
        'tomorrow': build_response(tomorrow, 'Tomorrow'),
        'day_after': build_response(day_after, day_names[day_after.weekday()])
    }


# ============ Stats Report Endpoint (Phase 8) ============

@router.get("/stats")
async def get_bookings_stats(
    from_date: date,
    to_date: date,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> dict:
    """
    Get comprehensive booking statistics with spend analysis (Phase 8).

    Calculates:
    - Total bookings and covers
    - Average lead time (days between booking and reservation)
    - Spend analysis (food/beverage/total) matched from SambaPOS
    - Resident vs non-resident split (by covers and spend)
    - Daily breakdown
    - Service period breakdown with avg spend per cover
    """
    from services.resos_stats import ResosStatsService

    # Get summary metrics from resos_bookings
    result = await db.execute(
        select(
            func.count(ResosBooking.id).label('total_bookings'),
            func.sum(ResosBooking.people).label('total_covers'),
            func.avg(
                ResosBooking.booking_date - func.cast(ResosBooking.booked_at, Date)
            ).label('avg_lead_time_days')
        ).where(
            and_(
                ResosBooking.kitchen_id == current_user.kitchen_id,
                ResosBooking.booking_date >= from_date,
                ResosBooking.booking_date <= to_date,
                func.lower(ResosBooking.status).in_(['seated', 'left', 'arrived', 'confirmed', 'approved'])
            )
        )
    )
    summary = result.first()

    total_bookings = summary.total_bookings or 0
    total_covers = summary.total_covers or 0
    avg_lead_time_days = float(summary.avg_lead_time_days) if summary.avg_lead_time_days else 0.0

    # Get resident/non-resident cover counts
    result = await db.execute(
        select(
            func.sum(case((ResosBooking.is_hotel_guest == True, ResosBooking.people), else_=0)).label('resident_covers'),
            func.sum(case((ResosBooking.is_hotel_guest == False, ResosBooking.people), else_=0)).label('non_resident_covers')
        ).where(
            and_(
                ResosBooking.kitchen_id == current_user.kitchen_id,
                ResosBooking.booking_date >= from_date,
                ResosBooking.booking_date <= to_date,
                func.lower(ResosBooking.status).in_(['seated', 'left', 'arrived', 'confirmed', 'approved'])
            )
        )
    )
    resident_split = result.first()
    resident_covers_booking = resident_split.resident_covers or 0
    non_resident_covers_booking = resident_split.non_resident_covers or 0

    # Get spend statistics (Phase 8 integration)
    stats_service = ResosStatsService(current_user.kitchen_id, db)
    spend_stats = await stats_service.get_spend_statistics(from_date, to_date)

    # Calculate resident percentages
    resident_pct_covers = (resident_covers_booking / total_covers * 100) if total_covers > 0 else 0.0
    total_spend = spend_stats['total_spend']
    resident_pct_spend = (spend_stats['resident_spend'] / total_spend * 100) if total_spend > 0 else 0.0

    # Combine booking data with spend data
    return {
        'summary': {
            'total_bookings': total_bookings,
            'total_covers': total_covers,
            'avg_lead_time_days': round(avg_lead_time_days, 1),
            'resident_covers': resident_covers_booking,
            'non_resident_covers': non_resident_covers_booking,
            'resident_pct_covers': round(resident_pct_covers, 1),
            'resident_pct_spend': round(resident_pct_spend, 1)
        },
        'spend': {
            'total_spend': spend_stats['total_spend'],
            'food_spend': spend_stats['food_spend'],
            'beverage_spend': spend_stats['beverage_spend'],
            'resident_spend': spend_stats['resident_spend'],
            'non_resident_spend': spend_stats['non_resident_spend'],
            'total_tickets': spend_stats['total_tickets'],
            'resident_tickets': spend_stats['resident_tickets'],
            'non_resident_tickets': spend_stats['non_resident_tickets'],
            'matched_to_resos': spend_stats['matched_to_resos'],
            'unmatched_to_resos': spend_stats['unmatched_to_resos'],
            'classification': spend_stats['classification']
        },
        'daily_breakdown': spend_stats['daily_breakdown'],
        'service_period_breakdown': spend_stats['service_period_breakdown'],
        'daily_service_breakdown': spend_stats['daily_service_breakdown']
    }


# ============ Resident Covers for Budget ============

@router.get("/resident-covers")
async def get_resident_covers(
    start_date: date,
    end_date: date,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
) -> dict:
    """
    Get per-date, per-service-period hotel guest (resident) cover counts.
    Used by the Budget page to show 'inc Residents' row in the forecast table.
    """
    excluded_statuses = ['canceled', 'cancelled', 'waitlist', 'deleted', 'declined', 'rejected']

    # Query bookings grouped by date and opening_hour
    result = await db.execute(
        select(
            ResosBooking.booking_date,
            ResosBooking.opening_hour_id,
            ResosBooking.opening_hour_name,
            func.sum(ResosBooking.people).label('resident_covers'),
            func.count(ResosBooking.id).label('resident_bookings'),
        ).where(
            and_(
                ResosBooking.kitchen_id == current_user.kitchen_id,
                ResosBooking.booking_date >= start_date,
                ResosBooking.booking_date <= end_date,
                ResosBooking.is_hotel_guest == True,
                ~func.lower(ResosBooking.status).in_(excluded_statuses)
            )
        ).group_by(
            ResosBooking.booking_date,
            ResosBooking.opening_hour_id,
            ResosBooking.opening_hour_name
        )
    )

    # Get kitchen settings for service type mapping
    settings_result = await db.execute(
        select(KitchenSettings).where(KitchenSettings.kitchen_id == current_user.kitchen_id)
    )
    settings = settings_result.scalar_one_or_none()
    opening_hours_mapping = settings.resos_opening_hours_mapping if settings else None

    service_type_map = {}
    if opening_hours_mapping:
        for mapping in opening_hours_mapping:
            if isinstance(mapping, dict):
                resos_id = mapping.get('resos_id', '')
                service_type = mapping.get('service_type', '')
                if resos_id and service_type:
                    service_type_map[resos_id] = service_type

    # Build per-date, per-period response with covers and booking counts
    dates: dict[str, dict[str, dict[str, int]]] = {}
    for row in result:
        date_str = row.booking_date.isoformat()
        if date_str not in dates:
            dates[date_str] = {}

        opening_hour_id = row.opening_hour_id
        opening_hour_name = row.opening_hour_name or 'Unknown'
        service_type = service_type_map.get(opening_hour_id, opening_hour_name) if opening_hour_id else opening_hour_name
        period = service_type.lower() if service_type else 'unknown'

        # Accumulate in case multiple opening hours map to same period
        if period not in dates[date_str]:
            dates[date_str][period] = {"covers": 0, "bookings": 0}
        dates[date_str][period]["covers"] += row.resident_covers or 0
        dates[date_str][period]["bookings"] += row.resident_bookings or 0

    return {"dates": dates}
