from sqlalchemy.orm import Session, joinedload
from typing import Optional, List
from .models import User, Userprofile, Sellerprofile, Address


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


def get_user_by_email(db: Session, email: str) -> Optional[User]:
    return db.query(User).filter(User.email == email).first()


def list_all(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[User]:
    query = db.query(User)
    if filters.get("role"):
        query = query.filter(User.role == filters["role"])
    if filters.get("is_active") is not None:
        query = query.filter(User.is_active == filters["is_active"])
    if filters.get("is_verified") is not None:
        query = query.filter(User.is_verified == filters["is_verified"])
    return query.order_by(User.created_at.desc()).limit(limit).offset(offset).all()


def create(db: Session, data: dict) -> User:
    user = User(**data)
    db.add(user)
    db.flush()
    return user


def update(db: Session, entity_id: str, data: dict) -> Optional[User]:
    user = db.query(User).filter(User.id == entity_id).first()
    if not user:
        return None
    for key, value in data.items():
        setattr(user, key, value)
    db.flush()
    return user


def delete(db: Session, entity_id: str) -> bool:
    user = db.query(User).filter(User.id == entity_id).first()
    if not user:
        return False
    db.delete(user)
    db.flush()
    return True


def get_with_details(db: Session, entity_id: str) -> Optional[User]:
    return (
        db.query(User)
        .options(
            joinedload(User.user_profile),
            joinedload(User.seller_profile)
        )
        .filter(User.id == entity_id)
        .first()
    )


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


def get_userprofile_by_user_id(db: Session, user_id: str) -> Optional[Userprofile]:
    return db.query(Userprofile).filter(Userprofile.user_id == user_id).first()


def list_all_userprofiles(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[Userprofile]:
    query = db.query(Userprofile)
    if filters.get("user_id"):
        query = query.filter(Userprofile.user_id == filters["user_id"])
    return query.order_by(Userprofile.created_at.desc()).limit(limit).offset(offset).all()


def create_userprofile(db: Session, data: dict) -> Userprofile:
    userprofile = Userprofile(**data)
    db.add(userprofile)
    db.flush()
    return userprofile


def update_userprofile(db: Session, entity_id: str, data: dict) -> Optional[Userprofile]:
    userprofile = db.query(Userprofile).filter(Userprofile.id == entity_id).first()
    if not userprofile:
        return None
    for key, value in data.items():
        setattr(userprofile, key, value)
    db.flush()
    return userprofile


def delete_userprofile(db: Session, entity_id: str) -> bool:
    userprofile = db.query(Userprofile).filter(Userprofile.id == entity_id).first()
    if not userprofile:
        return False
    db.delete(userprofile)
    db.flush()
    return True


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


def get_sellerprofile_by_user_id(db: Session, user_id: str) -> Optional[Sellerprofile]:
    return db.query(Sellerprofile).filter(Sellerprofile.user_id == user_id).first()


def list_all_sellerprofiles(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[Sellerprofile]:
    query = db.query(Sellerprofile)
    if filters.get("user_id"):
        query = query.filter(Sellerprofile.user_id == filters["user_id"])
    if filters.get("is_verified_seller") is not None:
        query = query.filter(Sellerprofile.is_verified_seller == filters["is_verified_seller"])
    return query.order_by(Sellerprofile.created_at.desc()).limit(limit).offset(offset).all()


def create_sellerprofile(db: Session, data: dict) -> Sellerprofile:
    sellerprofile = Sellerprofile(**data)
    db.add(sellerprofile)
    db.flush()
    return sellerprofile


def update_sellerprofile(db: Session, entity_id: str, data: dict) -> Optional[Sellerprofile]:
    sellerprofile = db.query(Sellerprofile).filter(Sellerprofile.id == entity_id).first()
    if not sellerprofile:
        return None
    for key, value in data.items():
        setattr(sellerprofile, key, value)
    db.flush()
    return sellerprofile


def delete_sellerprofile(db: Session, entity_id: str) -> bool:
    sellerprofile = db.query(Sellerprofile).filter(Sellerprofile.id == entity_id).first()
    if not sellerprofile:
        return False
    db.delete(sellerprofile)
    db.flush()
    return True


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


def list_all_addresses(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[Address]:
    query = db.query(Address)
    if filters.get("user_id"):
        query = query.filter(Address.user_id == filters["user_id"])
    if filters.get("address_type"):
        query = query.filter(Address.address_type == filters["address_type"])
    if filters.get("is_default") is not None:
        query = query.filter(Address.is_default == filters["is_default"])
    return query.order_by(Address.created_at.desc()).limit(limit).offset(offset).all()


def create_address(db: Session, data: dict) -> Address:
    address = Address(**data)
    db.add(address)
    db.flush()
    return address


def update_address(db: Session, entity_id: str, data: dict) -> Optional[Address]:
    address = db.query(Address).filter(Address.id == entity_id).first()
    if not address:
        return None
    for key, value in data.items():
        setattr(address, key, value)
    db.flush()
    return address


def delete_address(db: Session, entity_id: str) -> bool:
    address = db.query(Address).filter(Address.id == entity_id).first()
    if not address:
        return False
    db.delete(address)
    db.flush()
    return True