from __future__ import annotations

from app.models import OEEInput, OEEResult


def calculate_oee(payload: OEEInput | dict) -> OEEResult:
    entrada = payload if isinstance(payload, OEEInput) else OEEInput.model_validate(payload)

    tiempo_planificado = entrada.tiempo_turno_min - entrada.paradas_planificadas_min
    tiempo_operativo = tiempo_planificado - entrada.paradas_no_planificadas_min
    produccion_teorica = (tiempo_operativo * 60) / entrada.ciclo_ideal_seg

    disponibilidad = tiempo_operativo / tiempo_planificado
    rendimiento = (entrada.produccion_total * entrada.ciclo_ideal_seg) / (tiempo_operativo * 60)
    calidad = entrada.produccion_buena / entrada.produccion_total
    oee = disponibilidad * rendimiento * calidad

    factors = {
        "disponibilidad": disponibilidad,
        "rendimiento": rendimiento,
        "calidad": calidad,
    }
    cuello_botella = min(factors, key=factors.get)

    advertencias = _build_warnings(entrada, rendimiento, oee, produccion_teorica)
    recomendaciones = _build_recommendations(cuello_botella)

    return OEEResult(
        entrada=entrada,
        tiempo_planificado_min=round(tiempo_planificado, 4),
        tiempo_operativo_min=round(tiempo_operativo, 4),
        produccion_teorica=round(produccion_teorica, 4),
        disponibilidad=round(disponibilidad, 6),
        rendimiento=round(rendimiento, 6),
        calidad=round(calidad, 6),
        oee=round(oee, 6),
        cuello_botella=cuello_botella,
        clasificacion=_classify_oee(oee),
        nivel_color=_oee_color_level(oee),
        advertencias=advertencias,
        recomendaciones=recomendaciones,
    )


def _classify_oee(oee: float) -> str:
    if oee >= 0.85:
        return "Clase mundial"
    if oee >= 0.60:
        return "Aceptable con mejora"
    if oee >= 0.40:
        return "Bajo"
    return "Critico"


def _oee_color_level(oee: float) -> str:
    if oee >= 0.85:
        return "excelente"
    if oee >= 0.60:
        return "advertencia"
    if oee >= 0.40:
        return "bajo"
    return "critico"


def _build_warnings(
    entrada: OEEInput,
    rendimiento: float,
    oee: float,
    produccion_teorica: float,
) -> list[str]:
    warnings: list[str] = []

    if rendimiento > 1:
        warnings.append(
            "El rendimiento supera el 100%. Revise ciclo ideal, produccion total o tiempos declarados."
        )

    if oee > 1:
        warnings.append(
            "El OEE supera el 100%. El caso probablemente tiene datos inconsistentes."
        )

    if entrada.produccion_total > produccion_teorica * 1.1:
        warnings.append(
            "La produccion total esta muy por encima de la produccion teorica del periodo."
        )

    return warnings


def _build_recommendations(cuello_botella: str) -> list[str]:
    if cuello_botella == "disponibilidad":
        return [
            "Priorizar reduccion de paradas no planificadas.",
            "Separar paradas por causa para ubicar equipos o procesos criticos.",
        ]

    if cuello_botella == "rendimiento":
        return [
            "Revisar microparadas, velocidad real y ciclo ideal declarado.",
            "Comparar produccion real por hora contra capacidad teorica.",
        ]

    return [
        "Revisar rechazos, retrabajos y criterios de pieza buena.",
        "Analizar defectos por tipo para ubicar la mayor perdida de calidad.",
    ]
