from fastapi import APIRouter, Depends, HTTPException, status, Query, Request, UploadFile, File
from sqlalchemy.orm import Session, joinedload, load_only
from sqlalchemy import and_, or_, func, desc
from typing import List, Optional
from datetime import datetime, timedelta
from pathlib import Path
import uuid
import hashlib
from ...shared.config.database import get_db
from ...shared.config.logging_config import get_logger
from ...security.middleware.auth import get_current_user, authorize_roles
from ...shared.utils.sanitization import sanitize_text
from ...auth.models.user import User
from ...auth.models.role import Role
from ..models.room import Room, RoomStatus
from ...bookings.models.booking import Booking, BookingStatus
from ..models.room_maintenance import RoomMaintenance, MaintenanceType, MaintenanceStatus
from ...hotel_services.models.housekeeping_task import HousekeepingTask, HousekeepingStatus, HousekeepingType
from ..models.room_inspection import RoomInspection, InspectionType, InspectionStatus
from ..models.room_attribute import RoomAttribute
from ..services.room_assignment_service import RoomAssignmentService
from pydantic import BaseModel
from typing import Dict, Any

logger = get_logger(__name__)
router = APIRouter(prefix='/advanced-rooms', tags=['advanced-room-management'])


# ==================== Room Assignment Optimization ====================

@router.post('/assign-optimal-room')
async def assign_optimal_room(
    request_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Find the best available room for a booking based on preferences"""
    try:
        room_type_id = request_data.get('room_type_id')
        check_in_str = request_data.get('check_in')
        check_out_str = request_data.get('check_out')
        num_guests = request_data.get('num_guests', 1)
        guest_preferences = request_data.get('guest_preferences', {})
        exclude_room_ids = request_data.get('exclude_room_ids', [])
        
        if not room_type_id or not check_in_str or not check_out_str:
            raise HTTPException(status_code=400, detail='Missing required fields')
        
        check_in = datetime.fromisoformat(check_in_str.replace('Z', '+00:00'))
        check_out = datetime.fromisoformat(check_out_str.replace('Z', '+00:00'))
        
        best_room = RoomAssignmentService.find_best_room(
            db=db,
            room_type_id=room_type_id,
            check_in=check_in,
            check_out=check_out,
            num_guests=num_guests,
            guest_preferences=guest_preferences,
            exclude_room_ids=exclude_room_ids
        )
        
        if not best_room:
            return {
                'status': 'success',
                'data': {'room': None, 'message': 'No suitable room available'}
            }
        
        return {
            'status': 'success',
            'data': {
                'room': {
                    'id': best_room.id,
                    'room_number': best_room.room_number,
                    'floor': best_room.floor,
                    'view': best_room.view,
                    'status': best_room.status.value
                }
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get('/{room_id}/availability-calendar')
async def get_room_availability_calendar(
    room_id: int,
    start_date: str = Query(...),
    end_date: str = Query(...),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get detailed availability calendar for a room"""
    try:
        start = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
        end = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
        
        calendar = RoomAssignmentService.get_room_availability_calendar(
            db=db,
            room_id=room_id,
            start_date=start,
            end_date=end
        )
        
        if not calendar:
            raise HTTPException(status_code=404, detail='Room not found')
        
        return {'status': 'success', 'data': calendar}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ==================== Room Maintenance ====================

@router.get('/maintenance')
async def get_maintenance_records(
    room_id: Optional[int] = Query(None),
    status: Optional[str] = Query(None),
    maintenance_type: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get maintenance records with filtering"""
    try:
        # Check if user is staff (not admin) - staff should see their assigned records AND unassigned records
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_staff = role and role.name == 'staff'
        
        query = db.query(RoomMaintenance).options(
            joinedload(RoomMaintenance.room),
            joinedload(RoomMaintenance.assigned_staff)
        )
        
        # Filter by assigned_to for staff users - include unassigned records so they can pick them up
        if is_staff:
            query = query.filter(
                or_(
                    RoomMaintenance.assigned_to == current_user.id,
                    RoomMaintenance.assigned_to.is_(None)
                )
            )
        
        if room_id:
            query = query.filter(RoomMaintenance.room_id == room_id)
        if status:
            query = query.filter(RoomMaintenance.status == MaintenanceStatus(status))
        if maintenance_type:
            query = query.filter(RoomMaintenance.maintenance_type == MaintenanceType(maintenance_type))
        
        total = query.count()
        query = query.order_by(desc(RoomMaintenance.scheduled_start))
        
        offset = (page - 1) * limit
        records = query.offset(offset).limit(limit).all()
        
        result = []
        for record in records:
            # Get reported by user info
            reported_by_name = None
            if record.reported_by:
                reported_by_user = db.query(User).filter(User.id == record.reported_by).first()
                if reported_by_user:
                    reported_by_name = reported_by_user.full_name
            
            result.append({
                'id': record.id,
                'room_id': record.room_id,
                'room_number': record.room.room_number if record.room else None,
                'maintenance_type': record.maintenance_type.value,
                'status': record.status.value,
                'title': record.title,
                'description': record.description,
                'scheduled_start': record.scheduled_start.isoformat() if record.scheduled_start else None,
                'scheduled_end': record.scheduled_end.isoformat() if record.scheduled_end else None,
                'actual_start': record.actual_start.isoformat() if record.actual_start else None,
                'actual_end': record.actual_end.isoformat() if record.actual_end else None,
                'assigned_to': record.assigned_to,
                'assigned_staff_name': record.assigned_staff.full_name if record.assigned_staff else None,
                'reported_by': record.reported_by,
                'reported_by_name': reported_by_name,
                'priority': record.priority,
                'blocks_room': record.blocks_room,
                'estimated_cost': float(record.estimated_cost) if record.estimated_cost else None,
                'actual_cost': float(record.actual_cost) if record.actual_cost else None,
                'notes': record.notes,
                'completion_notes': record.completion_notes if hasattr(record, 'completion_notes') else None,
                'created_at': record.created_at.isoformat() if record.created_at else None,
                'updated_at': record.updated_at.isoformat() if record.updated_at else None,
            })
        
        return {
            'status': 'success',
            'data': {
                'maintenance_records': result,
                'pagination': {
                    'total': total,
                    'page': page,
                    'limit': limit,
                    'total_pages': (total + limit - 1) // limit
                }
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post('/maintenance')
async def create_maintenance_record(
    maintenance_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Create a new maintenance record"""
    try:
        # Check user role - housekeeping users can only report issues, not create full maintenance records
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_housekeeping = role and role.name == 'housekeeping'
        
        room = db.query(Room).filter(Room.id == maintenance_data.get('room_id')).first()
        if not room:
            raise HTTPException(status_code=404, detail='Room not found')
        
        # For housekeeping users, set defaults for quick issue reporting
        if is_housekeeping:
            # Housekeeping users can only create corrective/emergency maintenance
            maintenance_type = maintenance_data.get('maintenance_type', 'corrective')
            if maintenance_type not in ['corrective', 'emergency']:
                maintenance_type = 'corrective'
            maintenance_data['maintenance_type'] = maintenance_type
            # Default to high priority for housekeeping-reported issues
            if 'priority' not in maintenance_data:
                maintenance_data['priority'] = 'high'
            # Default to blocking room
            if 'blocks_room' not in maintenance_data:
                maintenance_data['blocks_room'] = True
        
        scheduled_start = datetime.fromisoformat(maintenance_data.get('scheduled_start', datetime.utcnow().isoformat()).replace('Z', '+00:00'))
        scheduled_end = None
        if maintenance_data.get('scheduled_end'):
            scheduled_end = datetime.fromisoformat(maintenance_data['scheduled_end'].replace('Z', '+00:00'))
        
        block_start = None
        block_end = None
        if maintenance_data.get('block_start'):
            block_start = datetime.fromisoformat(maintenance_data['block_start'].replace('Z', '+00:00'))
        if maintenance_data.get('block_end'):
            block_end = datetime.fromisoformat(maintenance_data['block_end'].replace('Z', '+00:00'))
        
        # Sanitize user input
        sanitized_title = sanitize_text(maintenance_data.get('title', 'Maintenance'))
        sanitized_description = sanitize_text(maintenance_data.get('description')) if maintenance_data.get('description') else None
        sanitized_notes = sanitize_text(maintenance_data.get('notes')) if maintenance_data.get('notes') else None
        
        maintenance = RoomMaintenance(
            room_id=maintenance_data['room_id'],
            maintenance_type=MaintenanceType(maintenance_data.get('maintenance_type', 'preventive')),
            status=MaintenanceStatus(maintenance_data.get('status', 'scheduled')),
            title=sanitized_title,
            description=sanitized_description,
            scheduled_start=scheduled_start,
            scheduled_end=scheduled_end,
            assigned_to=maintenance_data.get('assigned_to'),
            reported_by=current_user.id,
            estimated_cost=maintenance_data.get('estimated_cost'),
            blocks_room=maintenance_data.get('blocks_room', True),
            block_start=block_start,
            block_end=block_end,
            priority=maintenance_data.get('priority', 'medium'),
            notes=sanitized_notes
        )
        
        # Update room status if blocking and maintenance is active
        if maintenance.blocks_room and maintenance.status in [MaintenanceStatus.scheduled, MaintenanceStatus.in_progress]:
            # Only update if room is currently available
            if room.status == RoomStatus.available:
                room.status = RoomStatus.maintenance
        
        db.add(maintenance)
        db.commit()
        db.refresh(maintenance)
        
        return {
            'status': 'success',
            'message': 'Maintenance record created successfully',
            'data': {'maintenance_id': maintenance.id}
        }
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))


@router.put('/maintenance/{maintenance_id}')
async def update_maintenance_record(
    maintenance_id: int,
    maintenance_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Update a maintenance record"""
    try:
        maintenance = db.query(RoomMaintenance).filter(RoomMaintenance.id == maintenance_id).first()
        if not maintenance:
            raise HTTPException(status_code=404, detail='Maintenance record not found')
        
        # Check if user is staff (not admin) - staff can only update their own assigned records
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_staff = role and role.name == 'staff'
        
        if is_staff:
            # Staff can only update records assigned to them
            if maintenance.assigned_to != current_user.id:
                raise HTTPException(status_code=403, detail='You can only update maintenance assigned to you')
            # Staff can only update status and completion fields
            allowed_fields = {'status', 'actual_start', 'actual_end', 'completion_notes', 'actual_cost'}
            if any(key not in allowed_fields for key in maintenance_data.keys()):
                raise HTTPException(status_code=403, detail='You can only update status and completion information')
        
        # Update fields
        if 'status' in maintenance_data:
            new_status = MaintenanceStatus(maintenance_data['status'])
            
            # Only the assigned user can mark the maintenance as completed
            if new_status == MaintenanceStatus.completed:
                if not maintenance.assigned_to:
                    raise HTTPException(status_code=400, detail='Maintenance must be assigned before it can be marked as completed')
                if maintenance.assigned_to != current_user.id:
                    raise HTTPException(status_code=403, detail='Only the assigned staff member can mark this maintenance as completed')
            
            old_status = maintenance.status
            maintenance.status = new_status
            
            # Update room status based on maintenance status
            if maintenance.status == MaintenanceStatus.completed and maintenance.blocks_room:
                # Check if room has other active maintenance
                other_maintenance = db.query(RoomMaintenance).filter(
                    and_(
                        RoomMaintenance.room_id == maintenance.room_id,
                        RoomMaintenance.id != maintenance_id,
                        RoomMaintenance.blocks_room == True,
                        RoomMaintenance.status.in_([MaintenanceStatus.scheduled, MaintenanceStatus.in_progress])
                    )
                ).first()
                
                if not other_maintenance:
                    # Check if room has active bookings
                    from datetime import datetime
                    active_booking = db.query(Booking).filter(
                        and_(
                            Booking.room_id == maintenance.room_id,
                            Booking.status.in_([BookingStatus.confirmed, BookingStatus.checked_in]),
                            Booking.check_in_date <= datetime.utcnow(),
                            Booking.check_out_date > datetime.utcnow()
                        )
                    ).first()
                    
                    if active_booking:
                        maintenance.room.status = RoomStatus.occupied
                    else:
                        maintenance.room.status = RoomStatus.available
            elif maintenance.status in [MaintenanceStatus.scheduled, MaintenanceStatus.in_progress] and maintenance.blocks_room:
                # Set room to maintenance if it's not occupied
                if maintenance.room.status == RoomStatus.available:
                    maintenance.room.status = RoomStatus.maintenance
        
        if 'actual_start' in maintenance_data:
            maintenance.actual_start = datetime.fromisoformat(maintenance_data['actual_start'].replace('Z', '+00:00'))
        if 'actual_end' in maintenance_data:
            maintenance.actual_end = datetime.fromisoformat(maintenance_data['actual_end'].replace('Z', '+00:00'))
        if 'completion_notes' in maintenance_data:
            maintenance.completion_notes = sanitize_text(maintenance_data['completion_notes']) if maintenance_data['completion_notes'] else None
        if 'actual_cost' in maintenance_data:
            maintenance.actual_cost = maintenance_data['actual_cost']
        
        db.commit()
        
        return {
            'status': 'success',
            'message': 'Maintenance record updated successfully'
        }
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))


# ==================== Housekeeping Tasks ====================

@router.get('/housekeeping')
async def get_housekeeping_tasks(
    room_id: Optional[int] = Query(None),
    status: Optional[str] = Query(None),
    task_type: Optional[str] = Query(None),
    date: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    include_cleaning_rooms: bool = Query(True, description='Include rooms in cleaning status even without tasks'),
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Get housekeeping tasks with filtering. Also includes rooms in cleaning status."""
    try:
        # Check user role - housekeeping and staff users should only see their assigned tasks
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_admin = role and role.name == 'admin'
        is_housekeeping_or_staff = role and role.name in ('housekeeping', 'staff')
        
        # Build base query for filtering
        base_query = db.query(HousekeepingTask)
        
        # Filter by assigned_to for housekeeping and staff users (not admin)
        # But also include unassigned tasks so they can pick them up
        if is_housekeeping_or_staff:
            base_query = base_query.filter(
                or_(
                    HousekeepingTask.assigned_to == current_user.id,
                    HousekeepingTask.assigned_to.is_(None)
                )
            )
        
        if room_id:
            base_query = base_query.filter(HousekeepingTask.room_id == room_id)
        if status:
            base_query = base_query.filter(HousekeepingTask.status == HousekeepingStatus(status))
        if task_type:
            base_query = base_query.filter(HousekeepingTask.task_type == HousekeepingType(task_type))
        if date:
            try:
                # Handle different date formats
                if 'T' in date:
                    date_obj = datetime.fromisoformat(date.replace('Z', '+00:00')).date()
                else:
                    date_obj = datetime.strptime(date, '%Y-%m-%d').date()
                base_query = base_query.filter(func.date(HousekeepingTask.scheduled_time) == date_obj)
            except (ValueError, AttributeError) as date_error:
                logger.error(f'Error parsing date {date}: {str(date_error)}')
                raise HTTPException(status_code=400, detail=f'Invalid date format: {date}')
        
        # Get count before adding joins (to avoid duplicate counting)
        total = base_query.count()
        
        # Add eager loading and ordering for the actual data query
        query = base_query.options(
            joinedload(HousekeepingTask.room),
            joinedload(HousekeepingTask.assigned_staff)
        ).order_by(HousekeepingTask.scheduled_time)
        
        offset = (page - 1) * limit
        tasks = query.offset(offset).limit(limit).all()
        
        result = []
        task_room_ids = set()
        
        # Process existing tasks
        for task in tasks:
            try:
                task_room_ids.add(task.room_id)
                
                # Safely get room status
                room_status = None
                if task.room and hasattr(task.room, 'status') and task.room.status:
                    room_status = task.room.status.value if hasattr(task.room.status, 'value') else str(task.room.status)
                
                # Safely get assigned staff name
                assigned_staff_name = None
                if task.assigned_staff and hasattr(task.assigned_staff, 'full_name'):
                    assigned_staff_name = task.assigned_staff.full_name
                
                result.append({
                    'id': task.id,
                    'room_id': task.room_id,
                    'room_number': task.room.room_number if task.room and hasattr(task.room, 'room_number') else None,
                    'booking_id': task.booking_id,
                    'task_type': task.task_type.value if hasattr(task.task_type, 'value') else str(task.task_type),
                    'status': task.status.value if hasattr(task.status, 'value') else str(task.status),
                    'scheduled_time': task.scheduled_time.isoformat() if task.scheduled_time else None,
                    'started_at': task.started_at.isoformat() if task.started_at else None,
                    'completed_at': task.completed_at.isoformat() if task.completed_at else None,
                    'assigned_to': task.assigned_to,
                    'assigned_staff_name': assigned_staff_name,
                    'checklist_items': task.checklist_items if task.checklist_items else [],
                    'notes': task.notes,
                    'quality_score': task.quality_score,
                    'estimated_duration_minutes': task.estimated_duration_minutes,
                    'actual_duration_minutes': task.actual_duration_minutes,
                    'room_status': room_status,
                    'photos': task.photos if task.photos else []
                })
            except Exception as task_error:
                logger.error(f'Error processing task {task.id if task else "unknown"}: {str(task_error)}', exc_info=True)
                # Continue with next task instead of failing completely
                continue
        
        # Include rooms in cleaning status that don't have tasks (or have unassigned tasks for housekeeping users)
        if include_cleaning_rooms:
            rooms_query = db.query(Room).filter(Room.status == RoomStatus.cleaning)
            
            if room_id:
                rooms_query = rooms_query.filter(Room.id == room_id)
            
            # For housekeeping/staff users, also include rooms with unassigned tasks
            if is_housekeeping_or_staff:
                # Get room IDs with unassigned tasks
                unassigned_task_rooms = db.query(HousekeepingTask.room_id).filter(
                    and_(
                        HousekeepingTask.assigned_to.is_(None),
                        HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress])
                    )
                ).distinct().all()
                unassigned_room_ids = [r[0] for r in unassigned_task_rooms]
                
                # Include rooms in cleaning status OR rooms with unassigned tasks
                if unassigned_room_ids:
                    rooms_query = db.query(Room).filter(
                        or_(
                            Room.status == RoomStatus.cleaning,
                            Room.id.in_(unassigned_room_ids)
                        )
                    )
                    if room_id:
                        rooms_query = rooms_query.filter(Room.id == room_id)
            
            cleaning_rooms = rooms_query.all()
            
            # Add rooms in cleaning status that don't have tasks in current page results
            for room in cleaning_rooms:
                if room.id not in task_room_ids:
                    # Check if there are any pending tasks for this room
                    pending_tasks = db.query(HousekeepingTask).filter(
                        and_(
                            HousekeepingTask.room_id == room.id,
                            HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress])
                        )
                    ).all()
                    
                    # For housekeeping/staff, only show if there are unassigned tasks or if room is in cleaning
                    if is_housekeeping_or_staff:
                        has_unassigned = any(t.assigned_to is None for t in pending_tasks)
                        if not has_unassigned and room.status != RoomStatus.cleaning:
                            continue
                    
                    # Create a virtual task entry for rooms in cleaning status
                    result.append({
                        'id': None,  # No task ID since this is a room status entry
                        'room_id': room.id,
                        'room_number': room.room_number,
                        'booking_id': None,
                        'task_type': 'vacant',  # Default task type
                        'status': 'pending',
                        'scheduled_time': datetime.utcnow().isoformat(),
                        'started_at': None,
                        'completed_at': None,
                        'assigned_to': None,
                        'assigned_staff_name': None,
                        'checklist_items': [],
                        'notes': 'Room is in cleaning mode',
                        'quality_score': None,
                        'estimated_duration_minutes': None,
                        'actual_duration_minutes': None,
                        'room_status': room.status.value,
                        'is_room_status_only': True,  # Flag to indicate this is from room status, not a task
                        'photos': []
                    })
        
        # Update total count to include cleaning rooms
        if include_cleaning_rooms:
            total = len(result)
        
        return {
            'status': 'success',
            'data': {
                'tasks': result,
                'pagination': {
                    'total': total,
                    'page': page,
                    'limit': limit,
                    'total_pages': (total + limit - 1) // limit
                }
            }
        }
    except Exception as e:
        logger.error(f'Error fetching housekeeping tasks: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail='Failed to fetch housekeeping tasks')


@router.post('/housekeeping')
async def create_housekeeping_task(
    task_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Create a new housekeeping task"""
    try:
        # Check user role - housekeeping users can only assign tasks to themselves
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_admin = role and role.name == 'admin'
        is_housekeeping = role and role.name == 'housekeeping'
        
        room = db.query(Room).filter(Room.id == task_data.get('room_id')).first()
        if not room:
            raise HTTPException(status_code=404, detail='Room not found')
        
        scheduled_time = datetime.fromisoformat(task_data['scheduled_time'].replace('Z', '+00:00'))
        assigned_to = task_data.get('assigned_to')
        
        # Housekeeping users can only assign tasks to themselves
        if is_housekeeping and assigned_to and assigned_to != current_user.id:
            raise HTTPException(status_code=403, detail='Housekeeping users can only assign tasks to themselves')
        
        # If housekeeping user doesn't specify assigned_to, assign to themselves
        if is_housekeeping and not assigned_to:
            assigned_to = current_user.id
        
        # Sanitize user input
        sanitized_notes = sanitize_text(task_data.get('notes')) if task_data.get('notes') else None
        
        task = HousekeepingTask(
            room_id=task_data['room_id'],
            booking_id=task_data.get('booking_id'),
            task_type=HousekeepingType(task_data.get('task_type', 'vacant')),
            status=HousekeepingStatus(task_data.get('status', 'pending')),
            scheduled_time=scheduled_time,
            assigned_to=assigned_to,
            created_by=current_user.id,
            checklist_items=task_data.get('checklist_items', []),
            notes=sanitized_notes,
            estimated_duration_minutes=task_data.get('estimated_duration_minutes')
        )
        
        db.add(task)
        db.commit()
        db.refresh(task)
        
        # Send notification to assigned staff member if task is assigned
        if assigned_to:
            try:
                from ...notifications.routes.notification_routes import notification_manager
                task_data_notification = {
                    'id': task.id,
                    'room_id': task.room_id,
                    'room_number': room.room_number,
                    'task_type': task.task_type.value,
                    'status': task.status.value,
                    'scheduled_time': task.scheduled_time.isoformat() if task.scheduled_time else None,
                    'assigned_to': task.assigned_to,
                    'created_at': task.created_at.isoformat() if task.created_at else None
                }
                notification_data = {
                    'type': 'housekeeping_task_assigned',
                    'data': task_data_notification
                }
                # Send notification to the specific staff member
                await notification_manager.send_to_user(assigned_to, notification_data)
            except Exception as e:
                logger.error(f'Error sending housekeeping task notification: {str(e)}', exc_info=True)
        
        return {
            'status': 'success',
            'message': 'Housekeeping task created successfully',
            'data': {'task_id': task.id}
        }
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))


@router.put('/housekeeping/{task_id}')
async def update_housekeeping_task(
    task_id: int,
    task_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Update a housekeeping task"""
    try:
        task = db.query(HousekeepingTask).filter(HousekeepingTask.id == task_id).first()
        if not task:
            raise HTTPException(status_code=404, detail='Housekeeping task not found')
        
        # Check user role - housekeeping and staff users can only update their own assigned tasks
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_admin = role and role.name == 'admin'
        is_housekeeping_or_staff = role and role.name in ('housekeeping', 'staff')
        
        if is_housekeeping_or_staff:
            # Housekeeping and staff can start unassigned tasks (assign to themselves)
            if task.assigned_to is None:
                # Allow housekeeping users to assign unassigned tasks to themselves
                if 'status' in task_data and task_data['status'] == 'in_progress':
                    task.assigned_to = current_user.id
                    task_data['assigned_to'] = current_user.id
            elif task.assigned_to != current_user.id:
                # If task is assigned, only the assigned user can update it
                raise HTTPException(status_code=403, detail='You can only update tasks assigned to you')
            # Housekeeping and staff cannot change assignment of already assigned tasks
            if 'assigned_to' in task_data and task.assigned_to is not None and task_data.get('assigned_to') != task.assigned_to:
                raise HTTPException(status_code=403, detail='You cannot change task assignment')
        
        old_assigned_to = task.assigned_to
        assigned_to_changed = False
        
        # Handle assignment - admin can assign, housekeeping can self-assign unassigned tasks
        if 'assigned_to' in task_data:
            if is_admin:
                new_assigned_to = task_data.get('assigned_to')
                if new_assigned_to != old_assigned_to:
                    task.assigned_to = new_assigned_to
                    assigned_to_changed = True
            elif is_housekeeping_or_staff and task.assigned_to is None:
                # Housekeeping can assign unassigned tasks to themselves when starting
                if task_data.get('assigned_to') == current_user.id:
                    task.assigned_to = current_user.id
                    assigned_to_changed = True
        
        if 'status' in task_data:
            new_status = HousekeepingStatus(task_data['status'])
            
            # Only the assigned user can mark the task as completed
            if new_status == HousekeepingStatus.completed:
                if not task.assigned_to:
                    raise HTTPException(status_code=400, detail='Task must be assigned before it can be marked as completed')
                if task.assigned_to != current_user.id:
                    raise HTTPException(status_code=403, detail='Only the assigned staff member can mark this task as completed')
            
            task.status = new_status
            
            if new_status == HousekeepingStatus.in_progress and not task.started_at:
                task.started_at = datetime.utcnow()
                # If task was unassigned, assign it to the current user
                if task.assigned_to is None and is_housekeeping_or_staff:
                    task.assigned_to = current_user.id
            elif new_status == HousekeepingStatus.completed and not task.completed_at:
                task.completed_at = datetime.utcnow()
                if task.started_at:
                    duration = (task.completed_at - task.started_at).total_seconds() / 60
                    task.actual_duration_minutes = int(duration)
                
                # Update room status when housekeeping task is completed
                room = db.query(Room).filter(Room.id == task.room_id).first()
                if room:
                    # Check if there are other pending housekeeping tasks for this room
                    pending_tasks = db.query(HousekeepingTask).filter(
                        and_(
                            HousekeepingTask.room_id == room.id,
                            HousekeepingTask.id != task.id,
                            HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress])
                        )
                    ).count()
                    
                    # Check if there's active maintenance
                    from ...rooms.models.room_maintenance import RoomMaintenance, MaintenanceStatus
                    active_maintenance = db.query(RoomMaintenance).filter(
                        and_(
                            RoomMaintenance.room_id == room.id,
                            RoomMaintenance.blocks_room == True,
                            RoomMaintenance.status.in_([MaintenanceStatus.scheduled, MaintenanceStatus.in_progress])
                        )
                    ).first()
                    
                    if active_maintenance:
                        room.status = RoomStatus.maintenance
                    elif pending_tasks > 0:
                        # Keep room as cleaning if there are other pending tasks
                        room.status = RoomStatus.cleaning
                    else:
                        # No pending tasks and no maintenance - room is ready for check-in
                        # Check if there are any upcoming bookings for this room
                        from ...bookings.models.booking import Booking, BookingStatus
                        upcoming_booking = db.query(Booking).filter(
                            and_(
                                Booking.room_id == room.id,
                                Booking.status == BookingStatus.confirmed,
                                Booking.check_in_date <= datetime.utcnow() + timedelta(days=1)
                            )
                        ).first()
                        
                        if upcoming_booking:
                            # Room has upcoming booking, keep as available (ready for check-in)
                            room.status = RoomStatus.available
                        else:
                            # No upcoming bookings, room is available
                            room.status = RoomStatus.available
        
        if 'checklist_items' in task_data:
            task.checklist_items = task_data['checklist_items']
        if 'notes' in task_data:
            task.notes = sanitize_text(task_data['notes']) if task_data['notes'] else None
        if 'issues_found' in task_data:
            task.issues_found = sanitize_text(task_data['issues_found']) if task_data['issues_found'] else None
        if 'quality_score' in task_data:
            task.quality_score = task_data['quality_score']
        if 'inspected_by' in task_data:
            task.inspected_by = task_data['inspected_by']
            task.inspected_at = datetime.utcnow()
        if 'inspection_notes' in task_data:
            task.inspection_notes = sanitize_text(task_data['inspection_notes']) if task_data['inspection_notes'] else None
        if 'photos' in task_data:
            task.photos = task_data['photos']
        
        db.commit()
        db.refresh(task)
        
        # Send notification if assignment changed
        if assigned_to_changed and task.assigned_to:
            try:
                from ...notifications.routes.notification_routes import notification_manager
                room = db.query(Room).filter(Room.id == task.room_id).first()
                task_data_notification = {
                    'id': task.id,
                    'room_id': task.room_id,
                    'room_number': room.room_number if room else None,
                    'task_type': task.task_type.value,
                    'status': task.status.value,
                    'scheduled_time': task.scheduled_time.isoformat() if task.scheduled_time else None,
                    'assigned_to': task.assigned_to,
                    'updated_at': task.updated_at.isoformat() if task.updated_at else None
                }
                notification_data = {
                    'type': 'housekeeping_task_assigned',
                    'data': task_data_notification
                }
                # Send notification to the newly assigned staff member
                await notification_manager.send_to_user(task.assigned_to, notification_data)
            except Exception as e:
                logger.error(f'Error sending housekeeping task notification: {str(e)}', exc_info=True)
        
        return {
            'status': 'success',
            'message': 'Housekeeping task updated successfully'
        }
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))


@router.post('/housekeeping/{task_id}/upload-photo')
async def upload_housekeeping_task_photo(
    task_id: int,
    request: Request,
    image: UploadFile = File(...),
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Upload a photo for a housekeeping task"""
    try:
        task = db.query(HousekeepingTask).filter(HousekeepingTask.id == task_id).first()
        if not task:
            raise HTTPException(status_code=404, detail='Housekeeping task not found')
        
        # Check permissions - housekeeping users can only upload photos to their assigned tasks
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_housekeeping_or_staff = role and role.name in ('housekeeping', 'staff')
        
        if is_housekeeping_or_staff:
            if task.assigned_to != current_user.id:
                raise HTTPException(status_code=403, detail='You can only upload photos to tasks assigned to you')
        
        # Validate and process image
        from ...shared.utils.file_validation import validate_uploaded_image
        from ...shared.config.settings import settings
        from PIL import Image
        import io
        
        max_size = 5 * 1024 * 1024  # 5MB
        content = await validate_uploaded_image(image, max_size)
        
        # Optimize image
        img = Image.open(io.BytesIO(content))
        if img.mode in ('RGBA', 'LA', 'P'):
            img = img.convert('RGB')
        
        # Generate unique filename
        file_ext = Path(image.filename).suffix.lower() if image.filename else '.jpg'
        if file_ext not in ['.jpg', '.jpeg', '.png', '.webp']:
            file_ext = '.jpg'
        
        filename = f"housekeeping_task_{task_id}_{uuid.uuid4().hex[:8]}{file_ext}"
        upload_dir = Path(__file__).parent.parent.parent.parent / 'uploads' / 'housekeeping'
        upload_dir.mkdir(parents=True, exist_ok=True)
        
        file_path = upload_dir / filename
        
        # Save optimized image
        img.save(file_path, 'JPEG', quality=85, optimize=True)
        
        image_url = f'/uploads/housekeeping/{filename}'
        
        # Update task photos
        if task.photos is None:
            task.photos = []
        if not isinstance(task.photos, list):
            task.photos = []
        
        task.photos.append(image_url)
        db.commit()
        
        # Get full URL
        base_url = str(request.base_url).rstrip('/')
        full_url = f"{base_url}{image_url}"
        
        return {
            'status': 'success',
            'message': 'Photo uploaded successfully',
            'data': {
                'photo_url': image_url,
                'full_url': full_url,
                'photos': task.photos
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error uploading housekeeping task photo: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=f'Error uploading photo: {str(e)}')


@router.post('/housekeeping/{task_id}/report-maintenance-issue')
async def report_maintenance_issue_from_task(
    task_id: int,
    issue_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Quick maintenance issue reporting from housekeeping task"""
    try:
        task = db.query(HousekeepingTask).filter(HousekeepingTask.id == task_id).first()
        if not task:
            raise HTTPException(status_code=404, detail='Housekeeping task not found')
        
        # Check permissions - housekeeping users can only report issues for their assigned tasks
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_housekeeping = role and role.name == 'housekeeping'
        
        if is_housekeeping:
            if task.assigned_to != current_user.id:
                raise HTTPException(status_code=403, detail='You can only report issues for tasks assigned to you')
        
        room = db.query(Room).filter(Room.id == task.room_id).first()
        if not room:
            raise HTTPException(status_code=404, detail='Room not found')
        
        # Create maintenance record - sanitize user input
        title = sanitize_text(issue_data.get('title', f'Issue reported from Room {room.room_number}'))
        description = sanitize_text(issue_data.get('description', ''))
        if task.notes:
            description = f"Reported from housekeeping task.\n\nTask Notes: {sanitize_text(task.notes)}\n\nIssue Description: {description}".strip()
        else:
            description = f"Reported from housekeeping task.\n\nIssue Description: {description}".strip()
        
        maintenance = RoomMaintenance(
            room_id=task.room_id,
            maintenance_type=MaintenanceType(issue_data.get('maintenance_type', 'corrective')),
            status=MaintenanceStatus('scheduled'),
            title=title,
            description=description,
            scheduled_start=datetime.utcnow(),
            assigned_to=None,  # Will be assigned by admin/staff
            reported_by=current_user.id,
            priority=issue_data.get('priority', 'high'),
            blocks_room=issue_data.get('blocks_room', True),
            notes=sanitize_text(issue_data.get('notes', f'Reported from housekeeping task #{task_id}'))
        )
        
        # Update room status if blocking
        if maintenance.blocks_room and room.status == RoomStatus.available:
            room.status = RoomStatus.maintenance
        
        db.add(maintenance)
        db.commit()
        db.refresh(maintenance)
        
        # Send notification to admin/staff
        try:
            from ...notifications.routes.notification_routes import notification_manager
            notification_data = {
                'type': 'maintenance_request_created',
                'data': {
                    'maintenance_id': maintenance.id,
                    'room_id': room.id,
                    'room_number': room.room_number,
                    'title': maintenance.title,
                    'priority': maintenance.priority,
                    'reported_by': current_user.full_name,
                    'reported_at': maintenance.created_at.isoformat() if maintenance.created_at else None
                }
            }
            # Send to admin and staff roles
            await notification_manager.send_to_role('admin', notification_data)
            await notification_manager.send_to_role('staff', notification_data)
        except Exception as e:
            logger.error(f'Error sending maintenance notification: {str(e)}', exc_info=True)
        
        return {
            'status': 'success',
            'message': 'Maintenance issue reported successfully',
            'data': {'maintenance_id': maintenance.id}
        }
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f'Error reporting maintenance issue: {str(e)}', exc_info=True)
        raise HTTPException(status_code=500, detail=f'Error reporting issue: {str(e)}')


# ==================== Room Inspections ====================

@router.get('/inspections')
async def get_room_inspections(
    room_id: Optional[int] = Query(None),
    inspection_type: Optional[str] = Query(None),
    status: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Get room inspections with filtering"""
    try:
        # Check if user is staff or housekeeping (not admin) - they should only see their assigned inspections
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_staff_or_housekeeping = role and role.name in ('staff', 'housekeeping')
        
        query = db.query(RoomInspection)
        
        # Filter by inspected_by for staff and housekeeping users
        if is_staff_or_housekeeping:
            query = query.filter(RoomInspection.inspected_by == current_user.id)
        
        if room_id:
            query = query.filter(RoomInspection.room_id == room_id)
        if inspection_type:
            query = query.filter(RoomInspection.inspection_type == InspectionType(inspection_type))
        if status:
            query = query.filter(RoomInspection.status == InspectionStatus(status))
        
        total = query.count()
        query = query.order_by(desc(RoomInspection.scheduled_at))
        
        offset = (page - 1) * limit
        inspections = query.offset(offset).limit(limit).all()
        
        result = []
        for inspection in inspections:
            result.append({
                'id': inspection.id,
                'room_id': inspection.room_id,
                'room_number': inspection.room.room_number if inspection.room else None,
                'booking_id': inspection.booking_id,
                'inspection_type': inspection.inspection_type.value,
                'status': inspection.status.value,
                'scheduled_at': inspection.scheduled_at.isoformat() if inspection.scheduled_at else None,
                'started_at': inspection.started_at.isoformat() if inspection.started_at else None,
                'completed_at': inspection.completed_at.isoformat() if inspection.completed_at else None,
                'inspected_by': inspection.inspected_by,
                'inspector_name': inspection.inspector.full_name if inspection.inspector else None,
                'checklist_items': inspection.checklist_items,
                'overall_score': float(inspection.overall_score) if inspection.overall_score else None,
                'overall_notes': inspection.overall_notes,
                'issues_found': inspection.issues_found,
                'requires_followup': inspection.requires_followup,
                'created_at': inspection.created_at.isoformat() if inspection.created_at else None
            })
        
        return {
            'status': 'success',
            'data': {
                'inspections': result,
                'pagination': {
                    'total': total,
                    'page': page,
                    'limit': limit,
                    'total_pages': (total + limit - 1) // limit
                }
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.post('/inspections')
async def create_room_inspection(
    inspection_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Create a new room inspection"""
    try:
        # Check user role - housekeeping users can only create inspections for themselves
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_housekeeping = role and role.name == 'housekeeping'
        
        room = db.query(Room).filter(Room.id == inspection_data.get('room_id')).first()
        if not room:
            raise HTTPException(status_code=404, detail='Room not found')
        
        scheduled_at = datetime.fromisoformat(inspection_data['scheduled_at'].replace('Z', '+00:00'))
        inspected_by = inspection_data.get('inspected_by')
        
        # Housekeeping users can only assign inspections to themselves
        if is_housekeeping:
            if inspected_by and inspected_by != current_user.id:
                raise HTTPException(status_code=403, detail='Housekeeping users can only create inspections for themselves')
            inspected_by = current_user.id
        
        inspection = RoomInspection(
            room_id=inspection_data['room_id'],
            booking_id=inspection_data.get('booking_id'),
            inspection_type=InspectionType(inspection_data.get('inspection_type', 'routine')),
            status=InspectionStatus(inspection_data.get('status', 'pending')),
            scheduled_at=scheduled_at,
            inspected_by=inspected_by,
            created_by=current_user.id,
            checklist_items=inspection_data.get('checklist_items', []),
            checklist_template_id=inspection_data.get('checklist_template_id')
        )
        
        db.add(inspection)
        db.commit()
        db.refresh(inspection)
        
        return {
            'status': 'success',
            'message': 'Room inspection created successfully',
            'data': {'inspection_id': inspection.id}
        }
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))


@router.put('/inspections/{inspection_id}')
async def update_room_inspection(
    inspection_id: int,
    inspection_data: dict,
    current_user: User = Depends(authorize_roles('admin', 'staff', 'housekeeping')),
    db: Session = Depends(get_db)
):
    """Update a room inspection"""
    try:
        inspection = db.query(RoomInspection).filter(RoomInspection.id == inspection_id).first()
        if not inspection:
            raise HTTPException(status_code=404, detail='Room inspection not found')
        
        # Check if user is staff or housekeeping (not admin) - they can only update their own assigned inspections
        role = db.query(Role).filter(Role.id == current_user.role_id).first()
        is_staff_or_housekeeping = role and role.name in ('staff', 'housekeeping')
        
        if is_staff_or_housekeeping:
            # Staff and housekeeping can only update inspections assigned to them
            if inspection.inspected_by != current_user.id:
                raise HTTPException(status_code=403, detail='You can only update inspections assigned to you')
            # Staff and housekeeping can only update status and inspection results
            allowed_fields = {'status', 'checklist_items', 'overall_score', 'overall_notes', 'issues_found', 'requires_followup', 'followup_notes', 'photos'}
            if any(key not in allowed_fields for key in inspection_data.keys()):
                raise HTTPException(status_code=403, detail='You can only update status and inspection results')
        
        if 'status' in inspection_data:
            new_status = InspectionStatus(inspection_data['status'])
            
            # Only the assigned user can mark the inspection as completed
            if new_status == InspectionStatus.completed:
                if not inspection.inspected_by:
                    raise HTTPException(status_code=400, detail='Inspection must be assigned before it can be marked as completed')
                if inspection.inspected_by != current_user.id:
                    raise HTTPException(status_code=403, detail='Only the assigned inspector can mark this inspection as completed')
            
            inspection.status = new_status
            
            if new_status == InspectionStatus.in_progress and not inspection.started_at:
                inspection.started_at = datetime.utcnow()
            elif new_status == InspectionStatus.completed and not inspection.completed_at:
                inspection.completed_at = datetime.utcnow()
        
        if 'checklist_items' in inspection_data:
            inspection.checklist_items = inspection_data['checklist_items']
        if 'overall_score' in inspection_data:
            inspection.overall_score = inspection_data['overall_score']
        if 'overall_notes' in inspection_data:
            inspection.overall_notes = sanitize_text(inspection_data['overall_notes']) if inspection_data['overall_notes'] else None
        if 'issues_found' in inspection_data:
            inspection.issues_found = sanitize_text(inspection_data['issues_found']) if inspection_data['issues_found'] else None
        if 'photos' in inspection_data:
            inspection.photos = inspection_data['photos']
        if 'requires_followup' in inspection_data:
            inspection.requires_followup = inspection_data['requires_followup']
        if 'followup_notes' in inspection_data:
            inspection.followup_notes = sanitize_text(inspection_data['followup_notes']) if inspection_data['followup_notes'] else None
        if 'maintenance_request_id' in inspection_data:
            inspection.maintenance_request_id = inspection_data['maintenance_request_id']
        
        db.commit()
        
        return {
            'status': 'success',
            'message': 'Room inspection updated successfully'
        }
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=str(e))


# ==================== Room Status Board ====================

@router.get('/status-board')
async def get_room_status_board(
    floor: Optional[int] = Query(None),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get visual room status board with all rooms and their current status"""
    try:
        query = db.query(Room).options(joinedload(Room.room_type))
        if floor:
            query = query.filter(Room.floor == floor)
        
        rooms = query.order_by(Room.floor, Room.room_number).all()
        
        result = []
        for room in rooms:
            # Get current booking if any
            # Use load_only to avoid querying columns that don't exist in the database (rate_plan_id, group_booking_id)
            current_booking = db.query(Booking).options(
                joinedload(Booking.user),
                load_only(Booking.id, Booking.user_id, Booking.room_id, Booking.check_in_date, Booking.check_out_date, Booking.status)
            ).filter(
                and_(
                    Booking.room_id == room.id,
                    Booking.status.in_([BookingStatus.confirmed, BookingStatus.checked_in]),
                    Booking.check_in_date <= datetime.utcnow(),
                    Booking.check_out_date > datetime.utcnow()
                )
            ).first()
            
            # Get active maintenance
            active_maintenance = db.query(RoomMaintenance).filter(
                and_(
                    RoomMaintenance.room_id == room.id,
                    RoomMaintenance.blocks_room == True,
                    RoomMaintenance.status.in_([MaintenanceStatus.scheduled, MaintenanceStatus.in_progress])
                )
            ).first()
            
            # Get pending housekeeping tasks
            pending_housekeeping = db.query(HousekeepingTask).filter(
                and_(
                    HousekeepingTask.room_id == room.id,
                    HousekeepingTask.status == HousekeepingStatus.pending,
                    func.date(HousekeepingTask.scheduled_time) == datetime.utcnow().date()
                )
            ).count()
            
            result.append({
                'id': room.id,
                'room_number': room.room_number,
                'floor': room.floor,
                'status': room.status.value,
                'room_type': room.room_type.name if room.room_type else None,
                'current_booking': {
                    'id': current_booking.id,
                    'guest_name': current_booking.user.full_name if current_booking.user else 'Unknown',
                    'check_out': current_booking.check_out_date.isoformat()
                } if current_booking else None,
                'active_maintenance': {
                    'id': active_maintenance.id,
                    'title': active_maintenance.title,
                    'type': active_maintenance.maintenance_type.value
                } if active_maintenance else None,
                'pending_housekeeping_count': pending_housekeeping
            })
        
        return {
            'status': 'success',
            'data': {'rooms': result}
        }
    except Exception as e:
        import logging
        import traceback
        logger = logging.getLogger(__name__)
        logger.error(f'Error in get_room_status_board: {str(e)}')
        logger.error(f'Traceback: {traceback.format_exc()}')
        raise HTTPException(status_code=500, detail=str(e))

