"""Tier C: índice semanal publicado, graph Spain, digest push, benchmark enriquecido."""

from __future__ import annotations

import json
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.core.config import get_settings
from app.models import Application, Job, User
from app.services.wow_tier_b import portal_benchmark, remote_spain_graph, salary_index_es, telegram_status


def _snapshots_dir() -> Path:
    d = get_settings().data_dir / "salary_index"
    d.mkdir(parents=True, exist_ok=True)
    return d


def publish_weekly_index(db: Session, admin: User | None = None) -> dict[str, Any]:
    """Genera snapshot semanal + post LinkedIn-ready + PDF."""
    idx = salary_index_es(db)
    rem = remote_spain_graph(db)
    week = datetime.now(timezone.utc).strftime("%G-W%V")
    payload = {
        "week": week,
        "published_at": datetime.now(timezone.utc).isoformat(),
        "publisher": admin.email if admin else "system",
        "index": idx,
        "remote_spain": rem.get("totals"),
        "linkedin_post": _linkedin_post(week, idx, rem),
        "wow": "Índice salarial ES semanal publicado — lead magnet + moat de datos.",
    }
    path = _snapshots_dir() / f"{week}.json"
    path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
    pdf = _snapshots_dir() / f"{week}.pdf"
    _write_index_pdf(pdf, payload)
    payload["pdf"] = str(pdf.name)
    return payload


def list_weekly_indexes() -> list[dict[str, Any]]:
    items = []
    for p in sorted(_snapshots_dir().glob("*.json"), reverse=True):
        try:
            data = json.loads(p.read_text(encoding="utf-8"))
            items.append(
                {
                    "week": data.get("week"),
                    "published_at": data.get("published_at"),
                    "sample_size": (data.get("index") or {}).get("sample_size"),
                    "file": p.name,
                }
            )
        except Exception:
            continue
    return items


def get_weekly_index(week: str | None = None) -> dict[str, Any] | None:
    files = sorted(_snapshots_dir().glob("*.json"), reverse=True)
    if week:
        path = _snapshots_dir() / f"{week}.json"
        if not path.exists():
            return None
        return json.loads(path.read_text(encoding="utf-8"))
    if not files:
        return None
    return json.loads(files[0].read_text(encoding="utf-8"))


def weekly_index_pdf_path(week: str | None = None) -> Path | None:
    data = get_weekly_index(week)
    if not data:
        return None
    pdf = _snapshots_dir() / f"{data['week']}.pdf"
    if not pdf.exists():
        _write_index_pdf(pdf, data)
    return pdf


def _linkedin_post(week: str, idx: dict[str, Any], rem: dict[str, Any]) -> str:
    by_role = idx.get("by_role") or {}
    lines = [
        f"📊 Índice salarial JobsWorld · semana {week}",
        f"Muestra: {idx.get('sample_size')} ofertas ES/EUR del agregador.",
        "",
    ]
    for role, b in list(by_role.items())[:5]:
        lines.append(f"· {role}: mediana {b.get('median')} € · P75 {b.get('p75')} €")
    totals = rem.get("totals") or {}
    lines += [
        "",
        f"Remote + hire-from-Spain: {totals.get('remote_and_spain_ok', 0)} ofertas.",
        "",
        "Fuente: JobsWorld (datos propios, no tablas USA).",
        "#empleo #salarios #España #remote",
    ]
    return "\n".join(lines)


def _write_index_pdf(path: Path, payload: dict[str, Any]) -> None:
    c = canvas.Canvas(str(path), pagesize=A4)
    width, height = A4
    y = height - 48
    c.setFont("Helvetica-Bold", 16)
    c.drawString(40, y, f"JobsWorld Índice salarial ES · {payload.get('week')}")
    y -= 24
    c.setFont("Helvetica", 10)
    idx = payload.get("index") or {}
    lines = [
        f"Publicado: {payload.get('published_at')}",
        f"Muestra: {idx.get('sample_size')} · {idx.get('currency')}",
        "",
        "Por ciudad:",
    ]
    for k, b in (idx.get("by_city") or {}).items():
        lines.append(f"  {k}: P25 {b['p25']} · med {b['median']} · P75 {b['p75']} (n={b['n']})")
    lines += ["", "Por rol:"]
    for k, b in (idx.get("by_role") or {}).items():
        lines.append(f"  {k}: med {b['median']} · P75 {b['p75']} (n={b['n']})")
    lines += ["", "Post LinkedIn:", *(payload.get("linkedin_post") or "").splitlines()]
    for line in lines:
        if y < 40:
            c.showPage()
            y = height - 40
            c.setFont("Helvetica", 10)
        c.drawString(40, y, line[:110])
        y -= 13
    c.save()


def spain_friendly_graph(db: Session) -> dict[str, Any]:
    """Graph interactivo: fuentes × remote × spain-ok × english."""
    rem = remote_spain_graph(db)
    sources = rem.get("top_sources") or []
    max_c = max((s["count"] for s in sources), default=1)
    nodes = [
        {
            "id": s["source"],
            "label": s["source"],
            "count": s["count"],
            "weight": round(100 * s["count"] / max_c, 1),
        }
        for s in sources
    ]
    # Enrich with english-required share per source (sample)
    for n in nodes:
        src = n["id"]
        total = db.query(Job).filter(Job.source == src, Job.remote.is_(True)).count()
        en = (
            db.query(Job)
            .filter(Job.source == src, Job.remote.is_(True), Job.requires_english_fluent.is_(True))
            .count()
        )
        spain = (
            db.query(Job)
            .filter(Job.source == src, Job.remote.is_(True), Job.hire_from_spain_ok.is_(True))
            .count()
        )
        n["remote_total"] = total
        n["english_required"] = en
        n["spain_ok"] = spain
        n["spain_share_pct"] = round(100 * spain / total, 1) if total else 0
        n["english_share_pct"] = round(100 * en / total, 1) if total else 0

    return {
        "totals": rem.get("totals"),
        "insight": rem.get("insight"),
        "nodes": nodes,
        "edges": [
            {"from": "candidate_es", "to": n["id"], "strength": n["spain_share_pct"]}
            for n in nodes
            if n["spain_share_pct"] > 0
        ],
        "wow": "Graph «quién contrata remote-from-Spain»: ves fuentes amigas vs trampas de inglés.",
    }


def enriched_portal_benchmark(db: Session, user: User) -> dict[str, Any]:
    base = portal_benchmark(db, user)
    # Enrich with contact extraction rate & remote spain share
    rows = []
    for r in base.get("rows") or []:
        src = r["source"]
        jobs = db.query(Job).filter(Job.source == src).limit(400).all()
        with_contact = sum(1 for j in jobs if j.contact_email or j.contact_phone)
        remote_spain = sum(1 for j in jobs if j.remote and j.hire_from_spain_ok)
        n = max(1, len(jobs))
        quality = round(
            0.4 * (with_contact / n) * 100
            + 0.3 * ((r.get("response_proxy_pct") or 0))
            + 0.3 * (remote_spain / n) * 100,
            1,
        )
        rows.append(
            {
                **r,
                "contact_rate_pct": round(100 * with_contact / n, 1),
                "remote_spain_in_sample": remote_spain,
                "quality_score": quality,
                "recommendation": (
                    "Prioriza" if quality >= 55 else "Selectivo" if quality >= 35 else "Baja prioridad"
                ),
            }
        )
    rows.sort(key=lambda x: x["quality_score"], reverse=True)
    return {
        "rows": rows,
        "note": base.get("note"),
        "wow": "Benchmark enriquecido: calidad = contactos + tu conversión + Spain-friendly.",
    }


def daily_push_digest(db: Session, user: User) -> dict[str, Any]:
    """Payload para Web Notification / Telegram digest."""
    from app.services.intelligence import daily_digest, readiness_score

    dig = daily_digest(db, user)
    ready = readiness_score(db, user)
    title = f"JobsWorld · {len(dig.get('picks') or [])} picks hoy"
    body = (dig.get("headline") or "")[:140]
    tg = telegram_status()
    return {
        "notification": {"title": title, "body": body, "url": "/power"},
        "digest": dig,
        "readiness": {"score": ready.get("score"), "level": ready.get("level")},
        "telegram": tg,
        "wow": "Digest listo para push: Web Notification o Telegram cuando configures el bot.",
    }


def extension_dom_hints() -> dict[str, Any]:
    """Selectores / hints para content scripts LinkedIn / InfoJobs."""
    return {
        "version": 1,
        "sites": [
            {
                "host": "linkedin.com",
                "title": ["h1", ".job-details-jobs-unified-top-card__job-title", ".jobs-unified-top-card__job-title"],
                "company": [".job-details-jobs-unified-top-card__company-name", ".jobs-unified-top-card__company-name a"],
                "location": [".job-details-jobs-unified-top-card__bullet", ".jobs-unified-top-card__bullet"],
                "description": ["#job-details", ".jobs-description__content", ".jobs-box__html-content"],
            },
            {
                "host": "infojobs.net",
                "title": ["h1.ij-Heading", "h1"],
                "company": [".ij-OfferDetailCompany", "[data-testid='company-name']"],
                "location": [".ij-OfferDetailLocation", "[data-testid='job-location']"],
                "description": ["#prefijoPuesto", ".ij-OfferDescription"],
            },
            {
                "host": "indeed.com",
                "title": ["h1.jobsearch-JobInfoHeader-title", "h1"],
                "company": ["[data-company-name='true']", ".jobsearch-InlineCompanyRating a"],
                "location": ["[data-testid='job-location']"],
                "description": ["#jobDescriptionText"],
            },
        ],
        "wow": "Clipper DOM-aware: captura título/empresa/ubicación real en LinkedIn e InfoJobs.",
    }
