"""
baja_temeraria.py

Análisis de baja temeraria conforme al artículo 85 del Real Decreto
1098/2001 (Reglamento General de la Ley de Contratos de las
Administraciones Públicas, RGLCAP).

Implementa las cuatro reglas según número de licitadores:
  1 licitador  → baja > 25 puntos porcentuales del precio de licitación.
  2 licitadores → diferencia > 20 puntos porcentuales entre ambas.
  3 licitadores → inferiores en > 10 puntos a la media aritmética.
  4+ licitadores → inferiores en > 10% a la media; con recálculo iterativo
                   excluyendo ofertas inferiores en >10% (art. 85.4).

Equivalente Python del módulo baja-temeraria.js — mismo algoritmo,
misma signatura de retorno. Standard library only.

Autor:       LloretIA (https://lloretia.com)
Licencia:    MIT
Versión:     1.0.0
Normativa:   RD 1098/2001 art. 85 · Ley 9/2017 art. 149
Python:      3.10+
"""

from __future__ import annotations
import sys
import json
from dataclasses import dataclass, asdict, field
from typing import Any


@dataclass
class Resultado:
    """Resultado del análisis de baja temeraria."""

    temerarias: list[float]
    regla: str
    detalle: dict[str, Any] = field(default_factory=dict)


def analizar_ofertas(precio_licitacion: float, ofertas: list[float]) -> Resultado:
    """Analiza un conjunto de ofertas y detecta las anormalmente bajas.

    Args:
        precio_licitacion: Precio base de licitación (IVA excluido).
        ofertas: Lista de importes ofertados por cada licitador.

    Returns:
        Resultado con campos `temerarias` (lista de importes temerarios),
        `regla` (descripción de la regla aplicada del art. 85 RGLCAP),
        y `detalle` (medias, umbrales, etc.).
    """
    validas = [o for o in ofertas if isinstance(o, (int, float)) and o > 0]
    n = len(validas)

    if n == 0:
        return Resultado(temerarias=[], regla="Sin ofertas válidas para analizar", detalle={"licitadores": 0})

    # ── Regla 1: 1 licitador ──────────────────────────────
    if n == 1:
        oferta = validas[0]
        baja_pp = ((precio_licitacion - oferta) / precio_licitacion) * 100
        return Resultado(
            temerarias=[oferta] if baja_pp > 25 else [],
            regla="1 licitador: baja > 25 puntos porcentuales del precio de licitación",
            detalle={"licitadores": 1, "baja_pp": baja_pp, "umbral": 25},
        )

    # ── Regla 2: 2 licitadores ────────────────────────────
    if n == 2:
        ordenadas = sorted(validas, reverse=True)
        mayor, menor = ordenadas[0], ordenadas[1]
        diferencia_pp = ((mayor - menor) / mayor) * 100
        return Resultado(
            temerarias=[menor] if diferencia_pp > 20 else [],
            regla="2 licitadores: diferencia entre ambas > 20 puntos porcentuales",
            detalle={"licitadores": 2, "diferencia_pp": diferencia_pp, "umbral": 20},
        )

    # ── Regla 3: 3 licitadores ────────────────────────────
    if n == 3:
        media = sum(validas) / 3
        umbral_10 = media * 0.10
        temerarias = [o for o in validas if o < media - umbral_10]
        return Resultado(
            temerarias=temerarias,
            regla="3 licitadores: inferiores en > 10 puntos a la media aritmética",
            detalle={
                "licitadores": 3,
                "media": media,
                "umbral_10": umbral_10,
                "oferta_umbral": media - umbral_10,
            },
        )

    # ── Regla 4: 4 o más licitadores (iteración art. 85.4) ─
    media_inicial = sum(validas) / n
    media = media_inicial
    iteracion = False

    inferiores = [o for o in validas if o < media * 0.90]
    if inferiores:
        restantes = [o for o in validas if o >= media * 0.90]
        if restantes:
            media = sum(restantes) / len(restantes)
            iteracion = True

    umbral_10 = media * 0.10
    temerarias = [o for o in validas if o < media - umbral_10]

    return Resultado(
        temerarias=temerarias,
        regla=(
            "4+ licitadores: inferiores en > 10% a la media"
            + (" (con recálculo art. 85.4)" if iteracion else "")
        ),
        detalle={
            "licitadores": n,
            "media_inicial": media_inicial,
            "media_final": media,
            "iteracion_aplicada": iteracion,
            "umbral_10": umbral_10,
            "oferta_umbral": media - umbral_10,
        },
    )


def format_resultado(r: Resultado) -> str:
    """Formatea el resultado para consumo humano (CLI / logs)."""
    lines = [f"Regla aplicada: {r.regla}"]
    if r.temerarias:
        lines.append(
            "Ofertas temerarias: "
            + ", ".join(f"{o:.2f} €" for o in r.temerarias)
        )
    else:
        lines.append("Ofertas temerarias: ninguna")
    if r.detalle:
        lines.append("Detalle:")
        for k, v in r.detalle.items():
            if isinstance(v, float):
                lines.append(f"  · {k}: {v:.2f}")
            else:
                lines.append(f"  · {k}: {v}")
    return "\n".join(lines)


# ── CLI ───────────────────────────────────────────────────
# Uso: python baja_temeraria.py <precio_licitacion> <oferta1> <oferta2> ...
# Ejemplo: python baja_temeraria.py 100000 85000 78000 92000 88000 75000

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(
            "Uso: python baja_temeraria.py <precio_licitacion> <oferta1> <oferta2> ...",
            file=sys.stderr,
        )
        sys.exit(1)

    try:
        precio = float(sys.argv[1])
        ofertas_cli = [float(x) for x in sys.argv[2:]]
    except ValueError as e:
        print(f"Error de parsing: {e}", file=sys.stderr)
        sys.exit(1)

    resultado = analizar_ofertas(precio, ofertas_cli)
    print(format_resultado(resultado))
    print("\nJSON:")
    print(json.dumps(asdict(resultado), indent=2, default=float, ensure_ascii=False))
