""" Account related CRUD methods """
from typing import Any, Dict, List

from sqlmodel import Session, select

from fastapi import HTTPException

from app.models import Account, AccountCreate, EventData, Message, User, Catering, Musica, Fotografia, MobiliariDecoracio, EspaiPropi
import uuid
from .service import get_filtered_services, get_all_services
from .event_service import _validate_service_capacity, _get_service_price, calcular_disponibilidad_reducida, calcular_cantidad_por_tipo
from datetime import datetime, timedelta


def filter_services(session: Session, event_data, services: List[str], get_filtered: bool) -> Dict[str, List[dict]]:
    """
    Filtra los servicios disponibles según los requisitos del evento.
    Devuelve un diccionario con los servicios candidatos por tipo.
    """
    filtered = {}
    total_price = 0
    for tipo in services:

        # Caso especial para mobiliario y decoración
        if tipo == "mobiliario" or tipo == "decoracion":
            subtipo = tipo
            tipo = "mobiliari-decoracio"

        # Obtener servicios filtrados usando get_filtered_services
        if get_filtered:
            # Configurar los filtros básicos
            filters = {
                "type": tipo,
                "dia_semana": event_data.data_inici.weekday() + 1  # Obtener el día de la semana (0-6)
            }
            services_result = get_filtered_services(session=session, filters=filters)
        else:
            services_result = get_all_services(session=session)

        # Caso especial para mobiliario y decoración
        if tipo == "mobiliari-decoracio":
            services_temp = []
            for service in services_result.data:
                if service['mobiliari_decoracio']['service_type'] == subtipo:
                    services_temp.append(service)
            services_result.data = services_temp

        # Filtrar servicios adicionalmente por disponibilidad y capacidad
        valid_services = []
        min_price = float('inf')
        for service_data in services_result.data:
            if get_filtered:
                data_I = event_data.data_inici
                data_F = event_data.data_fi
                cantidad = 1
                if tipo == "mobiliari-decoracio":
                    if not service_data['mobiliari_decoracio']:
                        print(service_data['name'] + " no tiene mobiliari_decoracio" + service_data['id'])
                    cantidad = calcular_cantidad_por_tipo(service_data['mobiliari_decoracio']['tipologia'], event_data.num_invitats)
                if tipo == "catering":
                    cantidad = event_data.num_invitats
                # Verificar disponibilidad
                time_total = (data_F - data_I).total_seconds() / 3600  # Convertir a horas
                time_change = time_total // 4
                dispo, range =calcular_disponibilidad_reducida(session, service_data, tipo, event_data, time_change)
                if not dispo:
                    continue
                if range is None:
                    continue
                if range == 0:
                    data_I = data_I + timedelta(hours=time_change)
                    data_F = data_F - timedelta(hours=time_change)
                elif range == 1:
                    data_I = data_I + timedelta(hours=time_change*2)
                    data_F = data_F
                elif range == 2:
                    data_I = data_I
                    data_F = data_F - timedelta(hours=time_change*2)


                # Verificar capacidad
                if not _validate_service_capacity(
                    session=session,
                    service_id=service_data['id'],
                    data_inicio=data_I,
                    data_fin=data_F,
                    cantidad=cantidad
                ):
                    continue

                # Obtener el precio para el rango de fechas
                try:
                    price = _get_service_price(
                        session=session,
                        service_id=service_data['id'],
                        data_inicio=data_I,
                        data_fin=data_F
                    )
                    price_final = price * cantidad

                    # Verificar si el precio está dentro del presupuesto
                    if price_final <= event_data.pressupost - total_price:
                        valid_services.append(service_data)
                        if price_final < min_price:
                            min_price = price_final
                except Exception:
                    continue
        if tipo == "mobiliari-decoracio":
            filtered[subtipo] = valid_services
        else:
            filtered[tipo] = valid_services
        if get_filtered:
            total_price += min_price

    if total_price > event_data.pressupost:
        raise HTTPException(status_code=400, detail="No se ha encontrado ninguna combinación de servicios que cumpla con el presupuesto y la disponibilidad")
    return filtered
    