import pytest
from datetime import datetime, timedelta
from uuid import uuid4
from sqlmodel import Session, SQLModel, create_engine
from sqlalchemy.pool import StaticPool

from app.models import EventData, Service, ServiceType, AvailabilityRule
from app.crud.assistant import filter_services

# Configuración de la base de datos de prueba
@pytest.fixture(name="session")
def session_fixture():
    engine = create_engine(
        "sqlite://",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    SQLModel.metadata.create_all(engine)
    with Session(engine) as session:
        yield session

@pytest.fixture(name="event_data")
def event_data_fixture():
    return EventData(
        num_invitats=50,
        pressupost=1000.0,
        data_inici=datetime.now(),
        data_fi=datetime.now() + timedelta(days=1)
    )

def test_filter_services_basic(session: Session, event_data: EventData):
    # Crear un servicio de prueba
    service = Service(
        id=uuid4(),
        type=ServiceType.CATERING,
        name="Test Catering",
        description="Test Description"
    )
    session.add(service)
    
    # Crear regla de disponibilidad
    availability = AvailabilityRule(
        service_id=service.id,
        dias_semana=[event_data.data_inici.weekday() + 1],
        price=500.0
    )
    session.add(availability)
    session.commit()

    # Probar el filtrado
    result = filter_services(session, event_data, ["catering"])
    
    assert "catering" in result
    assert len(result["catering"]) > 0
    assert result["catering"][0]["name"] == "Test Catering"

def test_filter_services_mobiliari(session: Session, event_data: EventData):
    # Crear un servicio de mobiliario
    service = Service(
        id=uuid4(),
        type=ServiceType.MOBILIARI_DECORACIO,
        name="Test Mobiliari",
        description="Test Description"
    )
    session.add(service)
    
    # Crear regla de disponibilidad
    availability = AvailabilityRule(
        service_id=service.id,
        dias_semana=[event_data.data_inici.weekday() + 1],
        price=300.0
    )
    session.add(availability)
    session.commit()

    # Probar el filtrado
    result = filter_services(session, event_data, ["mobiliario"])
    
    assert "mobiliario" in result
    assert len(result["mobiliario"]) > 0
    assert result["mobiliario"][0]["name"] == "Test Mobiliari"

def test_filter_services_budget(session: Session, event_data: EventData):
    # Crear servicios con diferentes precios
    service1 = Service(
        id=uuid4(),
        type=ServiceType.CATERING,
        name="Expensive Catering",
        description="Test Description"
    )
    service2 = Service(
        id=uuid4(),
        type=ServiceType.CATERING,
        name="Cheap Catering",
        description="Test Description"
    )
    session.add_all([service1, service2])
    
    # Crear reglas de disponibilidad
    availability1 = AvailabilityRule(
        service_id=service1.id,
        dias_semana=[event_data.data_inici.weekday() + 1],
        price=1500.0  # Excede el presupuesto
    )
    availability2 = AvailabilityRule(
        service_id=service2.id,
        dias_semana=[event_data.data_inici.weekday() + 1],
        price=500.0  # Dentro del presupuesto
    )
    session.add_all([availability1, availability2])
    session.commit()

    # Probar el filtrado
    result = filter_services(session, event_data, ["catering"])
    
    assert "catering" in result
    assert len(result["catering"]) == 1
    assert result["catering"][0]["name"] == "Cheap Catering"

def test_filter_services_multiple_types(session: Session, event_data: EventData):
    # Crear servicios de diferentes tipos
    services = [
        Service(id=uuid4(), type=ServiceType.CATERING, name="Catering"),
        Service(id=uuid4(), type=ServiceType.MUSICA, name="Musica"),
        Service(id=uuid4(), type=ServiceType.FOTOGRAFIA, name="Fotografia")
    ]
    session.add_all(services)
    
    # Crear reglas de disponibilidad
    availabilities = [
        AvailabilityRule(
            service_id=service.id,
            dias_semana=[event_data.data_inici.weekday() + 1],
            price=300.0
        ) for service in services
    ]
    session.add_all(availabilities)
    session.commit()

    # Probar el filtrado
    result = filter_services(session, event_data, ["catering", "musica", "fotografia"])
    
    assert all(tipo in result for tipo in ["catering", "musica", "fotografia"])
    assert all(len(result[tipo]) > 0 for tipo in ["catering", "musica", "fotografia"]) 