""" Espai Propi CRUD operations """
from typing import List, Optional
from uuid import UUID
from sqlmodel import Session, select, func
from fastapi import HTTPException

from app.models import (
    EspaiPropi,
    EspaiPropiCreate,
    EspaiPropiUpdate,
    EspaiPropiOut,
    EspaiPropisOut,
    TipusEspaiPropi,
    User
)

def create_espai_propi(
    *,
    session: Session,
    espai_propi_in: EspaiPropiCreate,
    user: User
) -> EspaiPropiOut:
    """Create a new espai propi"""
    # Verificar que el tipo sea válido usando el enum
    try:
        TipusEspaiPropi(espai_propi_in.tipus)
    except ValueError:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid type. Must be one of: {', '.join([t.value for t in TipusEspaiPropi])}"
        )

    # Convert address to dict if it exists
    address_dict = None
    if espai_propi_in.address:
        address_dict = espai_propi_in.address.model_dump()

    # Create the espai propi
    espai_propi = EspaiPropi(
        **espai_propi_in.model_dump(exclude={"address"}),
        address=address_dict,
        account_id=user.id
    )
    session.add(espai_propi)
    session.commit()
    session.refresh(espai_propi)
    
    return EspaiPropiOut.model_validate(espai_propi)

def update_espai_propi(
    *,
    session: Session,
    espai_propi: EspaiPropi,
    espai_propi_in: EspaiPropiUpdate
) -> EspaiPropiOut:
    """Update an espai propi"""
    # Update fields if provided
    update_data = espai_propi_in.model_dump(exclude_unset=True)
    
    # Handle address separately
    if "address" in update_data:
        # Si address ya es un diccionario, lo usamos directamente
        if isinstance(update_data["address"], dict):
            address_dict = update_data["address"]
        else:
            # Si es un modelo Pydantic, convertimos a diccionario
            address_dict = update_data["address"].model_dump()
        update_data["address"] = address_dict
    
    for field, value in update_data.items():
        setattr(espai_propi, field, value)
    
    session.add(espai_propi)
    session.commit()
    session.refresh(espai_propi)
    
    return EspaiPropiOut.model_validate(espai_propi)

def get_espai_propi_by_id(
    *,
    session: Session,
    id: UUID
) -> EspaiPropiOut:
    """Get espai propi by ID"""
    espai_propi = session.get(EspaiPropi, id)
    if not espai_propi:
        raise HTTPException(status_code=404, detail="Espai propi not found")
    
    return EspaiPropiOut.model_validate(espai_propi)

def get_espai_propis(
    *,
    session: Session,
    skip: int = 0,
    limit: int = 100,
) -> EspaiPropisOut:
    """Get list of espai propis with filters"""
    # Build the base query
    query = select(EspaiPropi)
    # Get total count
    count = session.exec(select(func.count()).select_from(query.subquery())).one()
    # Get paginated results
    results = session.exec(query.offset(skip).limit(limit)).all()
    # Convert to output model
    espai_propis = [EspaiPropiOut.model_validate(espai_propi) for espai_propi in results]
    
    return EspaiPropisOut(data=espai_propis, count=count)

def get_espai_propis_by_account(
    *,
    session: Session,
    account_id: UUID,
    skip: int = 0,
    limit: int = 100
) -> EspaiPropisOut:
    """Get espai propis by account id with pagination"""
    # Count query
    count_statement = select(func.count(EspaiPropi.id)).where(
        EspaiPropi.account_id == account_id
    )
    count = session.exec(count_statement).one()
    
    # Results query
    statement = select(EspaiPropi).where(
        EspaiPropi.account_id == account_id
    ).offset(skip).limit(limit)
    
    results = session.exec(statement).all()
    
    # Convert to output model
    espai_propis = [EspaiPropiOut.model_validate(espai_propi) for espai_propi in results]
    
    return EspaiPropisOut(data=espai_propis, count=count)

def delete_espai_propi(
    *,
    session: Session,
    espai_propi: EspaiPropi
) -> None:
    """Delete an espai propi"""
    session.delete(espai_propi)
    session.commit() 