"""Tier A wow: War Room, negociación, radar skills, certificado ética, demo mode."""

from __future__ import annotations

import hashlib
from collections import Counter
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any

from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from sqlalchemy.orm import Session

from app.models import Application, CV, CVVersion, Job, JobScore, Profile, User
from app.services.health import seed_demo_pack
from app.services.intelligence import (
    career_path,
    daily_digest,
    dashboard_payload,
    readiness_score,
    salary_intelligence,
)

# Vocabulario tech/comercial frecuente en ES ofertas
_SKILL_TOKENS = [
    "python", "react", "typescript", "javascript", "java", "kotlin", "go", "rust",
    "node", "django", "fastapi", "spring", "docker", "kubernetes", "aws", "azure",
    "gcp", "terraform", "sql", "postgresql", "mysql", "mongodb", "redis",
    "graphql", "rest", "linux", "ci/cd", "git", "agile", "scrum", "jira",
    "salesforce", "crm", "negociacion", "negociación", "excel", "power bi",
    "tableau", "enfermer", "sap", "angular", "vue", "next.js", "flutter",
    "machine learning", "llm", "ollama", "devops", "sre", "microservicios",
]


def _pct(n: int, d: int) -> float:
    return round(100.0 * n / d, 1) if d else 0.0


def skills_radar(db: Session, user: User, top_n: int = 20) -> dict[str, Any]:
    """Comparador tú vs mercado a partir de top matches."""
    profile = user.profile
    my_skills = [str(s).lower().strip() for s in (profile.skills if profile else []) or [] if str(s).strip()]
    my_set = set(my_skills)

    top = (
        db.query(JobScore)
        .filter(JobScore.user_id == user.id)
        .order_by(JobScore.match_score.desc())
        .limit(top_n)
        .all()
    )
    market: Counter[str] = Counter()
    job_refs: list[dict[str, Any]] = []
    for s in top:
        j = db.get(Job, s.job_id)
        if not j:
            continue
        blob = f"{j.title} {' '.join(j.tags or [])} {(j.description or '')[:2000]}".lower()
        found = []
        for tok in _SKILL_TOKENS:
            if tok in blob:
                market[tok] += 1
                found.append(tok)
        # tags explícitos
        for t in j.tags or []:
            t2 = str(t).lower().strip()
            if len(t2) >= 2:
                market[t2] += 1
                found.append(t2)
        job_refs.append({"id": j.id, "title": j.title, "score": s.match_score, "skills_hit": sorted(set(found))[:8]})

    top_market = market.most_common(18)
    axes = []
    for skill, cnt in top_market:
        you_have = any(skill in m or m in skill for m in my_set) or skill in my_set
        demand = _pct(cnt, max(1, len(top)))
        axes.append(
            {
                "skill": skill,
                "market_demand_pct": demand,
                "you_have": you_have,
                "gap": not you_have and demand >= 25,
                "you_score": 100 if you_have else 0,
                "market_score": min(100, demand),
            }
        )

    gaps = [a["skill"] for a in axes if a["gap"]][:8]
    strengths = [a["skill"] for a in axes if a["you_have"]][:8]
    coverage = _pct(sum(1 for a in axes if a["you_have"]), max(1, len(axes)))

    return {
        "axes": axes,
        "gaps": gaps,
        "strengths": strengths,
        "coverage_pct": coverage,
        "sample_jobs": len(job_refs),
        "jobs": job_refs[:10],
        "your_skills": my_skills,
        "wow": "Radar tú vs mercado: ves el hueco de skills que te separa del top 20 — y qué potenciar primero.",
        "cta": "Añade 2 skills gap al CV aprobado esta semana.",
    }


def negotiation_playbook(
    db: Session,
    user: User,
    location: str | None = None,
    query: str | None = None,
    ask: int | None = None,
) -> dict[str, Any]:
    """Scripts ES de negociación anclados a Salary Intel."""
    loc = location or (user.profile.location if user.profile else "Spain") or "Spain"
    intel = salary_intelligence(db, user, location=loc, query=query)
    bands = intel.get("bands") or {}
    eur = bands.get("EUR") or next(iter(bands.values()), None)
    profile = user.profile
    floor = ask or (profile.salary_min if profile else None)

    if eur:
        anchor = int(eur["p75"])
        walkaway = int(eur["p25"])
        sweet = int(eur["median"])
    else:
        anchor, walkaway, sweet = 48000, 32000, 40000

    target = floor or sweet
    stretch = max(target, int(anchor * 0.97))

    scripts = [
        {
            "phase": "Primer contacto (sin salario publicado)",
            "you_say": (
                f"Antes de avanzar, ¿podéis compartir la banda salarial prevista para el rol? "
                f"En mi búsqueda en {loc} estoy trabajando en torno a {sweet:,}–{stretch:,} € brutos/año "
                f"(datos de mercado JobsWorld)."
            ).replace(",", "."),
            "why": "Anclas con dato de mercado, no con un número inventado.",
        },
        {
            "phase": "Cuando ellos preguntan primero «¿cuánto pedís?»",
            "you_say": (
                f"Prefiero entender el alcance y la banda de la plaza. Con la información actual, "
                f"mi rango objetivo está entre {sweet:,} y {stretch:,} €. "
                f"El P75 de roles similares en muestra es ~{anchor:,} €."
            ).replace(",", "."),
            "why": "Evitas anclar bajo; das banda + evidencia.",
        },
        {
            "phase": "Contraoferta baja",
            "you_say": (
                f"Agradezco la propuesta. Para aceptar, necesitaría acercarnos a {stretch:,} € "
                f"o compensar con {{{{variable / remoto / formación}}}}. "
                f"Mi walk-away realista está cerca de {max(walkaway, int(target * 0.9)):,} €."
            ).replace(",", "."),
            "why": "Separas salario fijo de package; defines suelo sin sonar rígido.",
        },
        {
            "phase": "Email de cierre (48h)",
            "you_say": (
                "Gracias por el proceso. Confirmo interés y quedo a la espera del paquete escrito "
                "(salario, variable, remoto, onboarding). Puedo firmar esta semana si encaja la banda."
            ),
            "why": "Urgencia suave + claridad documental.",
        },
    ]

    package_levers = [
        "Variable / bonus objetivo",
        "Días remoto / híbrido Valencia-Madrid",
        "Presupuesto formación / certificaciones",
        "Flex horario / 4×10 si aplica",
        "Equipo / presupuesto home office",
        "Revisión salarial a 6 meses por escrito",
    ]

    return {
        "filters": {"location": loc, "query": query or "", "ask": floor},
        "market": eur or bands,
        "numbers": {
            "anchor_p75": anchor,
            "median": sweet,
            "walkaway_p25": walkaway,
            "your_target": target,
            "stretch": stretch,
            "currency": "EUR",
        },
        "scripts": scripts,
        "package_levers": package_levers,
        "tips": intel.get("negotiation_tips") or [],
        "wow": "Negociación con scripts en español anclados a tu Salary Intel real — no plantillas USA.",
    }


def war_room(db: Session, user: User) -> dict[str, Any]:
    """Briefing semanal: digest + funnel + gaps + readiness + career."""
    ready = readiness_score(db, user)
    digest = daily_digest(db, user)
    dash = dashboard_payload(db, user)
    radar = skills_radar(db, user, top_n=20)
    career = career_path(db, user)
    since = datetime.now(timezone.utc) - timedelta(days=7)
    apps_week = (
        db.query(Application)
        .filter(Application.user_id == user.id, Application.updated_at >= since)
        .count()
    )

    week_plan = [
        f"Cierra readiness → {min(100, ready['score'] + 10)} (gap: {[b['label'] for b in ready['breakdown'] if b['points'] == 0][:2]})",
        f"Aplica a top {min(5, len(digest.get('picks') or []))} del digest con CV aprobado.",
        f"Cubre skills gap: {', '.join(radar['gaps'][:3]) or 'ninguno crítico'}.",
        "1 mock Interview Copilot + 1 email de negociación si hay oferta.",
    ]

    return {
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "week_of": since.date().isoformat(),
        "readiness": ready,
        "funnel": dash.get("funnel"),
        "funnel_conversion_pct": dash.get("funnel_conversion_pct"),
        "digest": {"headline": digest.get("headline"), "picks": (digest.get("picks") or [])[:5]},
        "skills": {"gaps": radar["gaps"], "strengths": radar["strengths"], "coverage_pct": radar["coverage_pct"]},
        "career_top": (career.get("paths") or [])[:3],
        "applications_week_signal": apps_week,
        "week_plan": week_plan,
        "wow": "War Room semanal: el informe que un headhunter cobraria 300€ — exportable a PDF.",
    }


def ethics_certificate(db: Session, user: User) -> dict[str, Any]:
    """Certificado de candidatura ética: CV aprobado + anti-spam."""
    approved = (
        db.query(CVVersion)
        .join(CV)
        .filter(CV.user_id == user.id, CVVersion.review_status == "approved")
        .order_by(CVVersion.id.desc())
        .all()
    )
    apps = db.query(Application).filter(Application.user_id == user.id).all()
    spammy = [a for a in apps if (a.status or "") in ("auto_spam", "bulk")]
    # Heurística: muchas apps en <1h sin CV version = riesgo
    with_cv = sum(1 for a in apps if a.cv_version_id)
    ratio = _pct(with_cv, max(1, len(apps)))

    checks = [
        {"id": "cv_approved", "ok": len(approved) >= 1, "label": "Al menos 1 CV con gate de aprobación humana"},
        {"id": "no_bulk_spam", "ok": len(spammy) == 0, "label": "Sin envíos marcados como bulk/spam"},
        {"id": "cv_linked_apps", "ok": ratio >= 50 or len(apps) == 0, "label": f"Candidaturas ligadas a CV ({ratio}%)"},
        {"id": "onboarding", "ok": bool(user.onboarding_done), "label": "Perfil/onboarding completo"},
        {"id": "human_review", "ok": True, "label": "JobsWorld no auto-envía sin aprobación (política producto)"},
    ]
    passed = sum(1 for c in checks if c["ok"])
    score = _pct(passed, len(checks))
    eligible = score >= 80 and len(approved) >= 1

    code_src = f"{user.id}|{user.email}|{len(approved)}|{score}|ethics-v1"
    code = hashlib.sha256(code_src.encode()).hexdigest()[:12].upper()

    return {
        "eligible": eligible,
        "score": score,
        "certificate_id": f"JW-ETH-{code}",
        "holder": {"name": user.name, "email": user.email},
        "checks": checks,
        "approved_cv_count": len(approved),
        "applications_total": len(apps),
        "issued_at": datetime.now(timezone.utc).isoformat(),
        "statement_es": (
            "El titular usa JobsWorld con revisión humana de CV antes del envío, "
            "sin automatismos de spam masivo. Apto para mostrar a RRHH / academias B2B."
            if eligible
            else "Aún no cumple el umbral ético. Aprueba un CV y vincula candidaturas."
        ),
        "wow": "Certificado ética exportable: prueba ante RRHH de que no eres un bot de spam.",
    }


def _write_pdf_lines(path: Path, title: str, lines: list[str]) -> Path:
    path.parent.mkdir(parents=True, exist_ok=True)
    c = canvas.Canvas(str(path), pagesize=A4)
    width, height = A4
    y = height - 48
    c.setFont("Helvetica-Bold", 16)
    c.drawString(40, y, title[:90])
    y -= 28
    c.setFont("Helvetica", 10)
    for raw in lines:
        for line in _wrap(raw, 95):
            if y < 40:
                c.showPage()
                y = height - 40
                c.setFont("Helvetica", 10)
            c.drawString(40, y, line)
            y -= 13
    c.save()
    return path


def _wrap(text: str, width: int) -> list[str]:
    text = (text or "").replace("\t", " ")
    if not text:
        return [""]
    words = text.split()
    rows: list[str] = []
    cur = ""
    for w in words:
        trial = f"{cur} {w}".strip()
        if len(trial) <= width:
            cur = trial
        else:
            if cur:
                rows.append(cur)
            cur = w
    if cur:
        rows.append(cur)
    return rows or [""]


def war_room_pdf(db: Session, user: User, out: Path) -> Path:
    data = war_room(db, user)
    lines = [
        f"Generado: {data['generated_at']}",
        f"Semana desde: {data['week_of']}",
        "",
        f"READINESS: {data['readiness']['score']}/100 — {data['readiness']['level']}",
        f"Funnel: {data['funnel']} · conversión {data['funnel_conversion_pct']}%",
        "",
        "DIGEST",
        data["digest"].get("headline") or "",
    ]
    for p in data["digest"].get("picks") or []:
        lines.append(f"  · [{p.get('score')}] {p.get('title')} @ {p.get('company')}")
    lines += ["", "SKILLS GAP", ", ".join(data["skills"]["gaps"]) or "—", "", "PLAN DE LA SEMANA"]
    lines += [f"  {i+1}. {w}" for i, w in enumerate(data["week_plan"])]
    lines += ["", data["wow"]]
    return _write_pdf_lines(out, "JobsWorld — War Room Semanal", lines)


def ethics_certificate_pdf(db: Session, user: User, out: Path) -> Path:
    data = ethics_certificate(db, user)
    lines = [
        f"ID: {data['certificate_id']}",
        f"Titular: {data['holder']['name']} <{data['holder']['email']}>",
        f"Emitido: {data['issued_at']}",
        f"Score ético: {data['score']}% · Elegible: {'SÍ' if data['eligible'] else 'NO'}",
        "",
        data["statement_es"],
        "",
        "CHECKS",
    ]
    for c in data["checks"]:
        lines.append(f"  [{'OK' if c['ok'] else 'NO'}] {c['label']}")
    lines += ["", data["wow"], "", "Verificable en JobsWorld Admin Health · ethics-v1"]
    return _write_pdf_lines(out, "Certificado de Candidatura Ética", lines)


def run_demo_mode(db: Session, admin: User) -> dict[str, Any]:
    """Tour automático: Demo Pack + perfil showcase + script narrado de 8 min."""
    pack = seed_demo_pack(db, admin)

    profile = admin.profile
    if not profile:
        profile = Profile(user_id=admin.id)
        db.add(profile)
        db.flush()

    profile.headline = "Full Stack · Valencia · abierto a remoto EU"
    profile.summary = (
        "Perfil demo JobsWorld: React/Python, híbrido Valencia, inglés conversacional. "
        "Diseñado para enseñar matching, CV gate, Salary Intel y Power Center en <8 min."
    )
    profile.skills = ["python", "react", "typescript", "docker", "postgresql", "fastapi", "sql"]
    profile.desired_roles = ["Desarrollador Full Stack", "Backend Python", "DevOps junior"]
    profile.job_categories = ["tech"]
    profile.keywords = ["valencia", "python", "react", "remote eu"]
    profile.location = "Valencia, Spain"
    profile.salary_min = 40000
    profile.salary_currency = "EUR"
    profile.english_fluent = False
    profile.remote_only = False
    profile.experience_years = 5
    profile.seniority = "mid"
    profile.target_countries = ["ES", "EU"]
    admin.onboarding_done = True

    # CV base + versión aprobada si faltan
    cv = db.query(CV).filter(CV.user_id == admin.id).first()
    if not cv:
        cv = CV(user_id=admin.id, title="CV Demo Showcase", content_md="")
        db.add(cv)
        db.flush()
    md = (
        "# Admin Demo\n\n## Perfil\nFull Stack Valencia.\n\n"
        "## Skills\nPython, React, TypeScript, Docker, PostgreSQL, FastAPI.\n\n"
        "## Experiencia\n5 años producto SaaS B2B.\n"
    )
    if not (cv.content_md or "").strip():
        cv.content_md = md
    approved = (
        db.query(CVVersion)
        .filter(CVVersion.cv_id == cv.id, CVVersion.review_status == "approved")
        .first()
    )
    if not approved:
        ver = CVVersion(
            cv_id=cv.id,
            kind="improved",
            language="es",
            content_md=md,
            review_status="approved",
            sections_json={},
            base_snapshot_md=md,
            notes="Demo aprobado — showcase",
        )
        db.add(ver)

    db.commit()

    from app.services.scrape_service import recompute_scores_for_users

    recompute_scores_for_users(db)
    db.commit()

    ready = readiness_score(db, admin)
    digest = daily_digest(db, admin)
    radar = skills_radar(db, admin)
    script = [
        {
            "min": "0:00",
            "say": "Abrimos Landing → Pricing: planes editables por admin, tú tienes Carrera Max.",
            "go": "/pricing",
        },
        {
            "min": "0:45",
            "say": "Health Center: un botón prueba todo el producto. Score verde = listo para vender.",
            "go": "/admin/health",
        },
        {
            "min": "1:30",
            "say": "Power Center: Readiness Score, Daily Digest y Career Path. Esto no lo tiene InfoJobs.",
            "go": "/power",
        },
        {
            "min": "2:30",
            "say": "Cockpit + funnel. War Room PDF para el informe semanal del candidato.",
            "go": "/war-room",
        },
        {
            "min": "3:30",
            "say": "Radar tú vs mercado: gaps de skills visibles en 5 segundos.",
            "go": "/radar",
        },
        {
            "min": "4:30",
            "say": "Salary Intel + scripts de negociación en español anclados a datos reales.",
            "go": "/negotiate",
        },
        {
            "min": "5:30",
            "say": "Abre un top match: Company Brief + Interview Copilot + Simulador.",
            "go": f"/jobs/{digest['picks'][0]['id']}" if digest.get("picks") else "/feed",
        },
        {
            "min": "6:20",
            "say": "Certificado ética + plantillas CV sector — argumento B2B RRHH.",
            "go": "/ethics",
        },
        {
            "min": "7:00",
            "say": "Market Intel: índice ES público + remote-from-Spain. Esto es moat de datos.",
            "go": "/market",
        },
        {
            "min": "7:40",
            "say": "Personas pareja + cierre: ¿lo montamos para tu academia/equipo?",
            "go": "/personas",
        },
        {
            "min": "8:10",
            "say": "Fuentes ES/INT + Clipper Chrome. Pregunta de cierre comercial.",
            "go": "/sources",
        },
    ]

    return {
        "ok": True,
        "demo_pack": pack,
        "showcase_profile": {
            "headline": profile.headline,
            "skills": profile.skills,
            "location": profile.location,
            "salary_min": profile.salary_min,
        },
        "readiness": {"score": ready["score"], "level": ready["level"]},
        "digest_picks": len(digest.get("picks") or []),
        "radar_gaps": radar.get("gaps"),
        "script": script,
        "duration_min": 8,
        "wow": "Modo demo auto: en un clic dejas el producto listo y el guion de venta de 8 minutos.",
    }
