"""Health Center: diagnostica todas las capacidades de JobsWorld."""

from __future__ import annotations

import time
import traceback
from datetime import datetime, timezone
from typing import Any, Callable

from sqlalchemy.orm import Session

from app.core.config import get_settings
from app.models import (
    Application,
    CV,
    Job,
    JobAlert,
    JobSource,
    MarketingLead,
    Plan,
    ScrapeRun,
    User,
)
from app.scrapers import SCRAPER_CLASSES
from app.services import ai_cv
from app.services.entitlements import get_entitlements, get_plan_for_user
from app.services.intelligence import (
    career_path,
    company_brief,
    daily_digest,
    dashboard_payload,
    interview_prep,
    readiness_score,
    salary_intelligence,
)
from app.services.matching import score_job_for_profile
from app.services.portal_catalog import all_portal_definitions


def _check(name: str, category: str, fn: Callable[[], Any]) -> dict[str, Any]:
    t0 = time.perf_counter()
    try:
        detail = fn()
        ms = round((time.perf_counter() - t0) * 1000, 1)
        return {
            "name": name,
            "category": category,
            "ok": True,
            "ms": ms,
            "detail": detail if isinstance(detail, (str, int, float, bool, dict, list)) else str(detail)[:500],
        }
    except Exception as exc:  # noqa: BLE001
        ms = round((time.perf_counter() - t0) * 1000, 1)
        return {
            "name": name,
            "category": category,
            "ok": False,
            "ms": ms,
            "detail": f"{type(exc).__name__}: {exc}",
            "trace": traceback.format_exc()[-800:],
        }


def run_full_health(db: Session, admin: User, deep: bool = False) -> dict[str, Any]:
    settings = get_settings()
    checks: list[dict[str, Any]] = []

    checks.append(
        _check("database_ping", "core", lambda: {"users": db.query(User).count(), "jobs": db.query(Job).count()})
    )
    checks.append(_check("plans_seeded", "billing", lambda: {"plans": [p.key for p in db.query(Plan).all()]}))
    checks.append(
        _check(
            "admin_entitlements_max",
            "billing",
            lambda: (
                (lambda e: {"all_sources": e.get("all_sources"), "apply_run": e.get("apply_run"), "scrapes": e.get("scrapes_per_day")})(
                    get_entitlements(db, admin)
                )
            ),
        )
    )
    checks.append(
        _check(
            "admin_plan_carrera_max",
            "billing",
            lambda: {"plan": get_plan_for_user(db, admin).key},
        )
    )

    portals = all_portal_definitions()
    checks.append(
        _check(
            "portal_catalog",
            "scrapers",
            lambda: {
                "catalog": len(portals),
                "scrapers_registered": len(SCRAPER_CLASSES),
                "sources_db": db.query(JobSource).count(),
                "es": sum(1 for p in portals if p.get("region") == "es"),
                "intl": sum(1 for p in portals if p.get("region") == "intl"),
            },
        )
    )
    checks.append(
        _check(
            "bridge_scraper_instantiate",
            "scrapers",
            lambda: __import__("app.scrapers", fromlist=["get_scraper"]).get_scraper(
                "eures", {"search_url_template": "https://europa.eu/eures/portal/jv-se/home?keyword={query}", "queries": ["test"]}
            ).key,
        )
    )

    checks.append(_check("llm_status", "ai", lambda: ai_cv.llm_status()))
    if deep:
        checks.append(
            _check(
                "ai_improve_smoke",
                "ai",
                lambda: (ai_cv.improve_cv("# Perfil\nDemo JobsWorld", "es", "máximo 5 líneas")[:120] or "empty"),
            )
        )
    else:
        checks.append(
            {
                "name": "ai_improve_smoke",
                "category": "ai",
                "ok": True,
                "ms": 0,
                "detail": "omitido (pasa deep=1 para prueba IA completa)",
            }
        )

    job = db.query(Job).order_by(Job.id.desc()).first()
    if job:
        checks.append(
            _check(
                "matching_score",
                "intelligence",
                lambda: score_job_for_profile(job, admin.profile)[0] if admin.profile else 0,
            )
        )
        checks.append(_check("company_brief", "intelligence", lambda: company_brief(job).get("company")))
        if deep:

            def _iv():
                data = interview_prep(db, admin, job)
                return {"mode": data.get("mode"), "has_md": bool(data.get("markdown"))}

            checks.append(_check("interview_prep", "intelligence", _iv))
        else:
            checks.append(
                {
                    "name": "interview_prep",
                    "category": "intelligence",
                    "ok": True,
                    "ms": 0,
                    "detail": "omitido (pasa deep=1 — puede llamar LLM)",
                }
            )
    else:
        checks.append(
            {
                "name": "sample_job_features",
                "category": "intelligence",
                "ok": False,
                "ms": 0,
                "detail": "No hay jobs en DB — ejecuta Sync o Demo Pack",
            }
        )

    checks.append(_check("salary_intel", "intelligence", lambda: salary_intelligence(db, admin, location="Spain").get("sample_size")))

    def _dash():
        d = dashboard_payload(db, admin)
        return {"actions": len(d.get("next_actions") or []), "funnel": d.get("funnel"), "conversion": d.get("funnel_conversion_pct")}

    checks.append(_check("dashboard", "conversion", _dash))
    checks.append(
        _check(
            "readiness_score",
            "wow",
            lambda: (lambda r: {"score": r.get("score"), "level": r.get("level")})(readiness_score(db, admin)),
        )
    )
    checks.append(
        _check(
            "daily_digest",
            "wow",
            lambda: (lambda r: {"picks": len(r.get("picks") or []), "headline": r.get("headline")})(daily_digest(db, admin)),
        )
    )
    checks.append(
        _check(
            "career_path",
            "wow",
            lambda: {"paths": len(career_path(db, admin).get("paths") or [])},
        )
    )

    def _tier_a():
        from app.services.wow_tier_a import (
            ethics_certificate,
            negotiation_playbook,
            skills_radar,
            war_room,
        )

        wr = war_room(db, admin)
        rad = skills_radar(db, admin)
        neg = negotiation_playbook(db, admin, location="Spain")
        eth = ethics_certificate(db, admin)
        return {
            "war_room_plan": len(wr.get("week_plan") or []),
            "radar_axes": len(rad.get("axes") or []),
            "negotiate_scripts": len(neg.get("scripts") or []),
            "ethics_score": eth.get("score"),
            "ethics_eligible": eth.get("eligible"),
        }

    checks.append(_check("tier_a_suite", "wow", _tier_a))

    def _tier_b():
        from app.services import wow_tier_b as wb

        idx = wb.salary_index_es(db)
        rem = wb.remote_spain_graph(db)
        bench = wb.portal_benchmark(db, admin)
        tpls = wb.list_cv_templates()
        tg = wb.telegram_status()
        # interview score smoke
        sc = wb.score_interview_answer(
            "Cuéntame un logro",
            "En mi última empresa lideré una migración a FastAPI. Situación: monolito lento. "
            "Acción: reescribí APIs críticas con Python. Resultado: -40% latencia.",
            profile=admin.profile,
        )
        return {
            "templates": len(tpls),
            "salary_index_n": idx.get("sample_size"),
            "remote_spain_ok": rem.get("totals", {}).get("remote_and_spain_ok"),
            "portal_rows": len(bench.get("rows") or []),
            "interview_score_smoke": sc.get("score"),
            "telegram_configured": tg.get("configured"),
            "personas": len(wb.list_personas(db, admin)),
        }

    checks.append(_check("tier_b_suite", "wow", _tier_b))

    def _tier_c():
        from app.services import wow_tier_c as wc

        # ensure at least one snapshot for health
        if not wc.list_weekly_indexes():
            wc.publish_weekly_index(db, admin)
        graph = wc.spain_friendly_graph(db)
        bench = wc.enriched_portal_benchmark(db, admin)
        push = wc.daily_push_digest(db, admin)
        hints = wc.extension_dom_hints()
        return {
            "weekly": len(wc.list_weekly_indexes()),
            "graph_nodes": len(graph.get("nodes") or []),
            "bench_quality": (bench.get("rows") or [{}])[0].get("quality_score"),
            "push_title": (push.get("notification") or {}).get("title"),
            "dom_sites": len(hints.get("sites") or []),
        }

    checks.append(_check("tier_c_suite", "wow", _tier_c))

    def _tier_d():
        from app.services.wow_tier_d import golden_window, ghost_risk, mission_today

        job = db.query(Job).first()
        if not job:
            return {"jobs": 0}
        m = mission_today(db, admin)
        return {
            "window": golden_window(job).get("key"),
            "ghost": ghost_risk(job).get("level"),
            "mission_gold": len(m.get("golden") or []),
        }

    checks.append(_check("tier_d_suite", "wow", _tier_d))
    checks.append(
        _check(
            "cvs_table",
            "cv",
            lambda: db.query(CV).filter(CV.user_id == admin.id).count(),
        )
    )
    checks.append(_check("applications_table", "apply", lambda: db.query(Application).count()))
    checks.append(_check("alerts_table", "alerts", lambda: db.query(JobAlert).count()))
    checks.append(_check("marketing_leads", "marketing", lambda: db.query(MarketingLead).count()))

    def _launch_center():
        from app.services import launch as launch_svc

        origin = (launch_svc.get_social().get("public_base_url") or "http://test.local").rstrip("/")
        lands = launch_svc.list_landings(origin)
        social = launch_svc.get_social()
        ready = launch_svc.readiness(origin=origin, social=social, telegram_bot=False, campaigns=[])
        assert len(lands) >= 5
        assert "remoto-espana" in {L["slug"] for L in lands}
        csv = launch_svc.ads_csv(origin)
        assert "utm_campaign" in csv
        return {"landings": len(lands), "readiness_items": len(ready["items"]), "bio_url": f"{origin}/go"}

    checks.append(_check("launch_center", "marketing", _launch_center))
    checks.append(_check("scrape_runs", "scrapers", lambda: db.query(ScrapeRun).count()))

    # Feature matrix expected by product
    feature_matrix = [
        ("auth_login", True),
        ("plans_pricing", True),
        ("billing_me", True),
        ("feed_jobs", db.query(Job).count() >= 0),
        ("sources_es_intl", db.query(JobSource).count() >= 30),
        ("cv_studio", True),
        ("cv_review_gate", True),
        ("applications", True),
        ("onboarding", True),
        ("dashboard_cockpit", True),
        ("salary_intel", True),
        ("interview_copilot", True),
        ("company_brief", True),
        ("job_alerts", True),
        ("marketing_playbook", True),
        ("referral", True),
        ("admin_panel", True),
        ("entitlements", True),
        ("readiness_score", True),
        ("daily_digest", True),
        ("career_path", True),
        ("funnel_analytics", True),
        ("war_room", True),
        ("war_room_pdf", True),
        ("salary_negotiate", True),
        ("skills_radar", True),
        ("ethics_certificate", True),
        ("demo_mode", True),
        ("interview_simulator", True),
        ("cv_templates", True),
        ("salary_index_es", True),
        ("portal_benchmark", True),
        ("remote_spain_graph", True),
        ("search_personas", True),
        ("chrome_clipper", True),
        ("telegram_alerts_stub", True),
        ("weekly_salary_index", True),
        ("spain_graph", True),
        ("portal_benchmark_enriched", True),
        ("push_digest", True),
        ("extension_dom_hints", True),
        ("mobile_shell_pwa", True),
        ("ghost_detector", True),
        ("golden_window", True),
        ("anti_silence", True),
        ("buying_power_es", True),
        ("launch_ops", True),
        ("public_landings", True),
        ("social_compose", True),
    ]
    for name, ok in feature_matrix:
        checks.append({"name": f"feature:{name}", "category": "matrix", "ok": bool(ok), "ms": 0, "detail": "declared"})

    ok_n = sum(1 for c in checks if c.get("ok"))
    fail_n = len(checks) - ok_n
    score = round(100 * ok_n / max(1, len(checks)), 1)

    return {
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "app": "JobsWorld",
        "version": "2.5.0",
        "score": score,
        "ok": fail_n == 0,
        "summary": {"passed": ok_n, "failed": fail_n, "total": len(checks)},
        "environment": {
            "llm_provider": settings.llm_provider,
            "ollama_base_url": settings.ollama_base_url,
            "stripe_configured": bool(settings.stripe_secret_key),
            "api_port": settings.api_port,
        },
        "checks": checks,
        "recommendations": _recommendations(checks, db),
    }


def _recommendations(checks: list[dict[str, Any]], db: Session) -> list[str]:
    rec = []
    failed = [c for c in checks if not c.get("ok")]
    for c in failed:
        rec.append(f"Reparar «{c['name']}»: {c.get('detail')}")
    if db.query(Job).count() < 5:
        rec.append("Pocas ofertas: usa «Demo Pack» o Sync Fuentes ES para impresionar en demos.")
    llm = next((c for c in checks if c["name"] == "llm_status"), None)
    if llm and isinstance(llm.get("detail"), dict) and not llm["detail"].get("ollama_ok"):
        rec.append("Ollama no responde: Interview/CV IA usarán fallback o fallarán — revisa 192.168.1.16:11434.")
    if not rec:
        rec.append("Sistema saludable. Listo para demo comercial.")
    return rec


def seed_demo_pack(db: Session, admin: User) -> dict[str, Any]:
    """Crea ofertas demo impactantes si el feed está vacío/pobre."""
    from app.scrapers.base import JobDTO
    from app.services.scrape_service import upsert_job

    samples = [
        JobDTO(
            external_id="demo-valencia-fullstack",
            source="manual",
            title="Desarrollador/a Full Stack (híbrido Valencia)",
            company="NovaLabs Valencia",
            location="Valencia, España",
            remote=False,
            salary_min=38000,
            salary_max=48000,
            salary_currency="EUR",
            url="https://www.infojobs.net/jobsearch/search-results/list.xhtml?keyword=full+stack+valencia",
            description=(
                "Buscamos perfil full stack para producto SaaS. Stack: React, Python, PostgreSQL, Docker. "
                "Híbrido 2 días en oficina Valencia. Contacto: talent@novalabs.example. Inglés intermedio."
            ),
            lang="es",
            tags=["react", "python", "valencia", "hybrid"],
            requires_english_fluent=False,
            hire_from_spain_ok=True,
            raw={"demo": True},
        ),
        JobDTO(
            external_id="demo-remote-eu-devops",
            source="manual",
            title="DevOps / SRE Remote EU",
            company="Orbit Cloud",
            location="Remote EU",
            remote=True,
            salary_min=65000,
            salary_max=85000,
            salary_currency="EUR",
            url="https://es.indeed.com/jobs?q=devops+sre+remoto&l=Europa",
            description=(
                "Remote-first EU. Kubernetes, Terraform, AWS. Hiring from Spain OK. "
                "Email careers@orbitcloud.example. English useful but team has ES speakers."
            ),
            lang="en",
            tags=["devops", "kubernetes", "remote", "eu"],
            requires_english_fluent=False,
            hire_from_spain_ok=True,
            raw={"demo": True},
        ),
        JobDTO(
            external_id="demo-comercial-b2b",
            source="manual",
            title="Comercial B2B Sector Industrial",
            company="IberTrade",
            location="Madrid / Valencia",
            remote=False,
            salary_min=32000,
            salary_max=45000,
            salary_currency="EUR",
            url="https://www.infojobs.net/jobsearch/search-results/list.xhtml?keyword=comercial+b2b",
            description="Cartera de clientes industriales. CRM, negociación, visitas. Contacto rrhh@ibertrade.example",
            lang="es",
            tags=["sales", "b2b", "comercial"],
            requires_english_fluent=False,
            hire_from_spain_ok=True,
            raw={"demo": True},
        ),
        JobDTO(
            external_id="demo-us-remote-high",
            source="manual",
            title="Senior Backend Engineer (US Remote)",
            company="Atlantic Systems",
            location="Remote Worldwide",
            remote=True,
            salary_min=110000,
            salary_max=140000,
            salary_currency="USD",
            url="https://www.indeed.com/jobs?q=senior+backend+engineer+remote&l=remote",
            description="US company hiring worldwide. Strong English required. Python/Go. Apply via portal.",
            lang="en",
            tags=["backend", "remote", "us"],
            requires_english_fluent=True,
            hire_from_spain_ok=True,
            raw={"demo": True},
        ),
        JobDTO(
            external_id="demo-enfermeria",
            source="manual",
            title="Enfermero/a planta hospitalaria",
            company="Clínica Mediterránea",
            location="Valencia",
            remote=False,
            salary_min=28000,
            salary_max=34000,
            salary_currency="EUR",
            url="https://www.infojobs.net/jobsearch/search-results/list.xhtml?keyword=enfermero+valencia",
            description="Turnos rotatorios. Colegiación requerida. Contacto seleccion@clinicamed.example",
            lang="es",
            tags=["health", "enfermeria"],
            requires_english_fluent=False,
            hire_from_spain_ok=True,
            raw={"demo": True},
        ),
    ]
    created = 0
    for dto in samples:
        _, is_new = upsert_job(db, dto)
        if is_new:
            created += 1
    db.commit()
    from app.services.scrape_service import recompute_scores_for_users

    recompute_scores_for_users(db)
    db.commit()
    return {"created_or_seen": len(samples), "new": created, "jobs_total": db.query(Job).count()}
