from sqlalchemy.orm import Session, joinedload
from typing import Optional, List
from .models import Airport, Route


def get_by_id(db: Session, entity_id: str, model_class) -> Optional[Airport | Route]:
    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[Airport | Route]:
    query = db.query(model_class)
    
    if model_class == Airport:
        if filters.get("search"):
            search_term = f"%{filters['search']}%"
            query = query.filter(
                (Airport.code.ilike(search_term)) |
                (Airport.name.ilike(search_term)) |
                (Airport.city.ilike(search_term)) |
                (Airport.country.ilike(search_term))
            )
    elif model_class == Route:
        if filters.get("status"):
            query = query.filter(Route.status == filters["status"])
        if filters.get("origin_airport_id"):
            query = query.filter(Route.origin_airport_id == filters["origin_airport_id"])
        if filters.get("destination_airport_id"):
            query = query.filter(Route.destination_airport_id == filters["destination_airport_id"])
    
    return query.order_by(model_class.created_at.desc()).limit(limit).offset(offset).all()


def create(db: Session, data: dict, model_class) -> Airport | Route:
    instance = model_class(**data)
    db.add(instance)
    db.flush()
    return instance


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


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


def get_airport_by_code(db: Session, code: str) -> Optional[Airport]:
    return db.query(Airport).filter(Airport.code == code).first()


def get_route_with_details(db: Session, route_id: str) -> Optional[Route]:
    return (
        db.query(Route)
        .options(
            joinedload(Route.origin_airport),
            joinedload(Route.destination_airport)
        )
        .filter(Route.id == route_id)
        .first()
    )


def get_routes_by_airports(db: Session, origin_airport_id: str, destination_airport_id: str) -> List[Route]:
    return (
        db.query(Route)
        .filter(
            Route.origin_airport_id == origin_airport_id,
            Route.destination_airport_id == destination_airport_id
        )
        .all()
    )