from sqlalchemy.orm import Session, joinedload, subqueryload
from typing import Optional, List
from .models import Hotel, Hotelamenity, Roomtype, Transportation


def get_by_id(db: Session, entity_id: str, model_class) -> Optional[object]:
    return db.query(model_class).filter(model_class.id == entity_id).first()


def list_all(db: Session, model_class, limit: int = 20, offset: int = 0, **filters) -> List[object]:
    query = db.query(model_class)
    for key, value in filters.items():
        if value is not None and hasattr(model_class, key):
            query = query.filter(getattr(model_class, key) == value)
    return query.limit(limit).offset(offset).all()


def create(db: Session, model_class, data: dict) -> object:
    obj = model_class(**data)
    db.add(obj)
    db.flush()
    return obj


def update(db: Session, entity_id: str, model_class, data: dict) -> Optional[object]:
    obj = get_by_id(db, entity_id, model_class)
    if not obj:
        return None
    for key, value in data.items():
        setattr(obj, key, value)
    db.flush()
    return obj


def delete(db: Session, entity_id: str, model_class) -> bool:
    obj = get_by_id(db, entity_id, model_class)
    if not obj:
        return False
    db.delete(obj)
    db.flush()
    return True


def get_hotel_with_details(db: Session, hotel_id: str) -> Optional[Hotel]:
    return (
        db.query(Hotel)
        .options(
            joinedload(Hotel.service_provider).joinedload("Serviceprovider".user),
            joinedload(Hotel.room_types),
            joinedload(Hotel.hotel_amenities).joinedload(Hotelamenity.amenity),
        )
        .filter(Hotel.id == hotel_id)
        .first()
    )


def get_hotels_by_service_provider(db: Session, service_provider_id: str, limit: int = 20, offset: int = 0) -> List[Hotel]:
    return (
        db.query(Hotel)
        .filter(Hotel.service_provider_id == service_provider_id)
        .limit(limit)
        .offset(offset)
        .all()
    )


def get_room_types_by_hotel(db: Session, hotel_id: str) -> List[Roomtype]:
    return db.query(Roomtype).filter(Roomtype.hotel_id == hotel_id).all()


def get_transportations_by_service_provider(db: Session, service_provider_id: str, limit: int = 20, offset: int = 0) -> List[Transportation]:
    return (
        db.query(Transportation)
        .filter(Transportation.service_provider_id == service_provider_id)
        .limit(limit)
        .offset(offset)
        .all()
    )


def get_hotel_amenities_by_hotel(db: Session, hotel_id: str) -> List[Hotelamenity]:
    return db.query(Hotelamenity).filter(Hotelamenity.hotel_id == hotel_id).all()