"""Test end-to-end del pipeline AR-House con el escenario Jacksonville $70K.

Valida que los 3 bugs estan arreglados:
- Bug 1: outputs exhaustivos (>= 400 palabras/seccion en agentes tecnicos)
- Bug 2: CRITICAL_RED_FLAG detectado + inyectado a todos los agentes
- Bug 3: anomalias detectadas (Cap Rate >12%, etc.) + DealAnalyzer incluye
        seccion "Validacion de Inputs Requerida"

Corre los 8 agentes Ollama en secuencia (~5-8 min). Imprime status en stdout
y guarda JSON completo en analyses/. Al final hace assertions y prints
"PASS/FAIL" para cada bug.
"""
from __future__ import annotations

import io
import json
import sys
import time
from pathlib import Path

# Forzar stdout UTF-8 para Windows (los emojis en logs sino crashean cp1252)
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")

# Imports despues del fix de stdout
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))

from orchestrator import DealInputs, BuyerProfile, analyze_deal  # noqa: E402


def status_cb(msg: str) -> None:
    """Print status con timestamp."""
    print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)


def count_words(text: str) -> int:
    if not text:
        return 0
    return len(text.split())


def main() -> int:
    print("=" * 70)
    print("AR-House — End-to-end test: Jacksonville $70K (Bug 1+2+3)")
    print("=" * 70)

    # Escenario clasico "demasiado bueno para ser verdad" con ADDRESS REAL
    # 5005 N Pearl St (Duval PA confirmed: owner JONES JOHN N, RE# 027301-0000)
    # Precio $70K simulado + rent $1,500/mo → triggers suspicious_low + anomalias.
    # Con ENABLE_COURT_RECORDS=true, court_records debe popular owner_name.
    deal = DealInputs(
        address="5005 N Pearl St, Jacksonville, FL 32206",
        price=70_000,
        rent=1_500,
        property_tax=2_000,
        insurance=1_800,
        hoa=0,
        sqft=1_200,
        beds=3,
        baths=2.0,
        year_built=1985,
        arv=180_000,
        rehab_override=25_000,    # skipping PhotoInspector
        deal_type="mls",
    )
    profile = BuyerProfile(
        profile_class="C",
        fico=720,
        capital_available=50_000,
        nationality="Argentina",
    )

    print(f"\nDEAL: {deal.address}")
    print(f"  price={deal.price:,} rent={deal.rent:,}/mo arv={deal.arv:,}")
    print(f"  year_built={deal.year_built}, rehab_override={deal.rehab_override:,}")
    print()

    t0 = time.perf_counter()
    result = analyze_deal(deal, profile, photo_bytes=None, status_cb=status_cb)
    elapsed = time.perf_counter() - t0

    print()
    print("=" * 70)
    print(f"ANALISIS COMPLETADO en {elapsed:.0f}s")
    print("=" * 70)

    # ════════════════════════════════════════════════════════════
    # Validaciones automaticas
    # ════════════════════════════════════════════════════════════
    # analyze_deal devuelve AnalysisResult dataclass; los AgentResult internos
    # son convertidos a dict por asdict() en la construccion. Acceder via [key].
    # Wave 1.5A: check court records flow
    court = (result.verified_data or {}).get("court_records") or {}

    pv = result.price_validation or {}
    anomalies = (result.computed_scenarios or {}).get("anomalies", {})
    deal_an = (result.deal_analysis or {}).get("output", "") or ""
    coord = (result.final or {}).get("output", "") or ""
    research = (result.research or {}).get("output", "") or ""
    lender = (result.lender or {}).get("output", "") or ""
    value_est = (result.value_estimate or {}).get("output", "") or ""
    offer_str = (result.offer_strategy or {}).get("output", "") or ""
    briefing = (result.executive_briefing or {}).get("output", "") or ""

    print()
    print("─" * 70)
    print("WAVE 1.5A — Court Records Flow")
    print("─" * 70)
    print(f"  court_records.status: {court.get('status')}")
    print(f"  court_records.county: {court.get('county')}")
    print(f"  court_records.owner_name: {court.get('owner_name')}")
    print(f"  court_records.re_number: {court.get('re_number')}")
    print(f"  court_records.lis_pendens_count: {court.get('lis_pendens_count', 0)}")
    print(f"  sources_used: {court.get('sources_used', [])}")

    owner = court.get('owner_name') or ''
    owner_mentions = {
        "DealAnalyzer": owner in deal_an if owner else False,
        "FloridaResearcher": owner in research if owner else False,
        "LenderMatcher": owner in lender if owner else False,
        "Coordinator": owner in coord if owner else False,
        "ValueEstimator": owner in value_est if owner else False,
        "OfferStrategist": owner in offer_str if owner else False,
        "ContextualGlossaryAgent": owner in briefing if owner else False,
    }
    print(f"  Owner name '{owner}' mentions in agent outputs:")
    for agent, mentioned in owner_mentions.items():
        print(f"    {agent}: {'✅' if mentioned else '⚠️'}")
    wave15a_pass = (
        court.get('status') in ('OWNER_VERIFIED', 'LIS_PENDENS_ACTIVE')
        and bool(owner)
        and sum(owner_mentions.values()) >= 2
    )
    print(f"  → Wave 1.5A flow: {'✅ PASS' if wave15a_pass else '⚠️ PARTIAL/FAIL'}")

    print()
    print("─" * 70)
    print("BUG 2 — Price Discrepancy Detection")
    print("─" * 70)
    pv_status = pv.get("status")
    pv_disc = pv.get("signed_max_discrepancy_pct")
    print(f"  price_validation.status: {pv_status}")
    print(f"  signed_max_discrepancy_pct: {pv_disc}")
    print(f"  sources_used: {pv.get('sources_used', [])}")
    bug2_pass = pv_status in ("CRITICAL_RED_FLAG", "WARNING")
    print(f"  → Bug 2 detection: {'✅ PASS' if bug2_pass else '❌ FAIL (status not flagging)'}")

    # ¿El red flag se inyecto en los prompts? Verificamos por el efecto:
    # ¿los agentes lo mencionan en sus outputs?
    flag_mentions = {
        "DealAnalyzer": "red flag" in deal_an.lower() or "precio anomalo" in deal_an.lower()
                       or "anomalo" in deal_an.lower() or "investigacion" in deal_an.lower()
                       or "investigación" in deal_an.lower() or "due diligence" in deal_an.lower(),
        "FloridaResearcher": "red flag" in research.lower() or "anomalo" in research.lower()
                            or "discrepancia" in research.lower(),
        "LenderMatcher": "red flag" in lender.lower() or "anomalo" in lender.lower()
                        or "validar" in lender.lower(),
        "Coordinator": "red flag" in coord.lower() or "anomalo" in coord.lower()
                      or "alerta" in coord.lower(),
        "ValueEstimator": "red flag" in value_est.lower() or "anomalo" in value_est.lower()
                         or "discrepancia" in value_est.lower(),
        "OfferStrategist": "red flag" in offer_str.lower() or "anomalo" in offer_str.lower(),
        "ContextualGlossaryAgent": ("alerta" in briefing.lower() or "🚨" in briefing
                                    or "precio anomalo" in briefing.lower()
                                    or "ANOMALO" in briefing),
    }
    print("  Mencion del red flag en outputs:")
    for agent, mentioned in flag_mentions.items():
        print(f"    {agent}: {'✅' if mentioned else '⚠️'}")

    print()
    print("─" * 70)
    print("BUG 3 — Anomaly Detection")
    print("─" * 70)
    print(f"  has_anomalies: {anomalies.get('has_anomalies')}")
    print(f"  is_critical: {anomalies.get('is_critical')}")
    print(f"  count: {anomalies.get('anomaly_count')} "
          f"(HIGH={anomalies.get('high_severity_count')}, MEDIUM={anomalies.get('medium_severity_count')})")
    if anomalies.get("flagged_metrics"):
        print("  flagged_metrics:")
        for f in anomalies["flagged_metrics"]:
            print(f"    - {f['scenario']} / {f['metric']} = {f['value']} ({f['severity']})")
    bug3_python_pass = anomalies.get("has_anomalies", False)
    print(f"  → Bug 3 Python detection: {'✅ PASS' if bug3_python_pass else '❌ FAIL'}")

    # ¿DealAnalyzer incluyo la seccion obligatoria "Validacion de Inputs"?
    has_validation_section = (
        "validacion de inputs" in deal_an.lower()
        or "validación de inputs" in deal_an.lower()
        or "validar inputs" in deal_an.lower()
    )
    print(f"  DealAnalyzer incluye '## ⚠️ Validacion de Inputs Requerida': "
          f"{'✅ PASS' if has_validation_section else '❌ FAIL — modelo se la salteo'}")

    print()
    print("─" * 70)
    print("BUG 1 — Exhaustividad (mínimo 400 palabras por agente técnico)")
    print("─" * 70)
    word_counts = {
        "DealAnalyzer": count_words(deal_an),
        "FloridaResearcher": count_words(research),
        "LenderMatcher": count_words(lender),
        "Coordinator": count_words(coord),
        "ValueEstimator": count_words(value_est),
        "OfferStrategist": count_words(offer_str),
    }
    bug1_pass = True
    for agent, wc in word_counts.items():
        symbol = "✅" if wc >= 400 else "⚠️"
        print(f"  {agent}: {wc} palabras {symbol}")
        if wc < 400:
            bug1_pass = False
    # ContextualGlossaryAgent SI puede ser mas corto (es el briefing)
    print(f"  ContextualGlossaryAgent (briefing — sin minimo): {count_words(briefing)} palabras")
    print(f"  → Bug 1 exhaustividad: "
          f"{'✅ PASS' if bug1_pass else '⚠️ PARTIAL (algunos agentes <400)'}")

    print()
    print("=" * 70)
    print("RESUMEN GLOBAL")
    print("=" * 70)
    print(f"  Bug 1 (exhaustividad): {'✅ PASS' if bug1_pass else '⚠️ PARTIAL'}")
    print(f"  Bug 2 (price red flag): {'✅ PASS' if bug2_pass else '❌ FAIL'}")
    print(f"  Bug 3 (anomalias): {'✅ PASS' if bug3_python_pass else '❌ FAIL'}")
    print(f"  Bug 3 (LLM secciona): {'✅ PASS' if has_validation_section else '❌ FAIL'}")
    print(f"  Total: {elapsed:.0f}s")

    # Excerpt de cada agente para ojo humano
    print()
    print("=" * 70)
    print("EXCERPTS (primeras 500 chars de cada agente)")
    print("=" * 70)
    for name, text in [
        ("DealAnalyzer", deal_an),
        ("Coordinator", coord),
        ("ContextualGlossaryAgent", briefing),
    ]:
        print(f"\n─── {name} ───")
        print(text[:500] + ("..." if len(text) > 500 else ""))

    return 0


if __name__ == "__main__":
    sys.exit(main())
