#!/usr/bin/env python3
"""
Modulo de rastreamento Dashboard Borrello.

- Endpoint /track/wa: registra clique em link de WhatsApp (com UTMs) e redireciona pro wa.me.
- Endpoint /track/lp: beacon pra registrar pageview da landing (chamado por GTM/JS).
- Helpers de agregacao usados pela aba /rastreamento do dashboard.

Registros em JSONL, um arquivo por evento tipo.
"""
from __future__ import annotations

import json
import os
import re
import urllib.parse
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Iterable

from flask import Blueprint, request, redirect, jsonify

# ============================================================
# Config
# ============================================================
TRACKING_DIR = Path(
    os.environ.get(
        "BORRELLO_TRACKING_DIR",
        "/opt/mia/workspace/clientes/borrello/dashboard/tracking",
    )
)
TRACKING_DIR.mkdir(parents=True, exist_ok=True)

CLICKS_FILE = TRACKING_DIR / "clicks.jsonl"
PAGEVIEWS_FILE = TRACKING_DIR / "pageviews.jsonl"

# Numero padrao do WhatsApp Borrello (sem mascara, com DDI)
DEFAULT_WA_PHONE = os.environ.get("BORRELLO_WA_PHONE", "5511999999999")

UTM_FIELDS = (
    "utm_source",
    "utm_medium",
    "utm_campaign",
    "utm_content",
    "utm_term",
)

bp = Blueprint("tracking", __name__)


# ============================================================
# Helpers
# ============================================================
def _now_iso() -> str:
    return datetime.now(timezone.utc).isoformat(timespec="seconds")


def _client_ip() -> str:
    fwd = request.headers.get("X-Forwarded-For", "")
    if fwd:
        return fwd.split(",")[0].strip()
    return request.headers.get("X-Real-IP") or request.remote_addr or ""


def _collect_utms() -> dict:
    out = {}
    for k in UTM_FIELDS:
        v = (request.args.get(k) or "").strip()
        if v:
            out[k] = v
    return out


def _append_jsonl(path: Path, record: dict) -> None:
    try:
        with path.open("a", encoding="utf-8") as f:
            f.write(json.dumps(record, ensure_ascii=False) + "\n")
    except Exception:
        pass


def _clean_phone(raw: str | None) -> str:
    if not raw:
        return DEFAULT_WA_PHONE
    digits = re.sub(r"\D", "", raw)
    return digits or DEFAULT_WA_PHONE


def _build_wa_url(phone: str, text: str) -> str:
    base = f"https://wa.me/{phone}"
    if text:
        return f"{base}?text={urllib.parse.quote(text)}"
    return base


# ============================================================
# Routes
# ============================================================
@bp.route("/track/wa", methods=["GET"])
def track_wa():
    utms = _collect_utms()
    phone = _clean_phone(request.args.get("phone"))
    text = (request.args.get("text") or "").strip()

    record = {
        "ts": _now_iso(),
        "ip": _client_ip(),
        "user_agent": request.headers.get("User-Agent", ""),
        "referer": request.headers.get("Referer", ""),
        "phone": phone,
        **utms,
    }
    _append_jsonl(CLICKS_FILE, record)

    return redirect(_build_wa_url(phone, text), code=302)


@bp.route("/track/lp", methods=["GET", "POST"])
def track_lp():
    utms = _collect_utms()

    extra = {}
    if request.is_json:
        try:
            body = request.get_json(silent=True) or {}
            for k in UTM_FIELDS:
                if not utms.get(k) and body.get(k):
                    utms[k] = str(body[k]).strip()
            for k in ("page", "title", "path", "event"):
                if body.get(k):
                    extra[k] = str(body[k])[:300]
        except Exception:
            pass

    for k in ("page", "title", "path", "event"):
        v = (request.args.get(k) or "").strip()
        if v and k not in extra:
            extra[k] = v[:300]

    record = {
        "ts": _now_iso(),
        "ip": _client_ip(),
        "user_agent": request.headers.get("User-Agent", ""),
        "referer": request.headers.get("Referer", ""),
        **utms,
        **extra,
    }
    _append_jsonl(PAGEVIEWS_FILE, record)

    resp = jsonify({"ok": True})
    resp.headers["Access-Control-Allow-Origin"] = "*"
    resp.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
    resp.headers["Access-Control-Allow-Headers"] = "Content-Type"
    return resp


@bp.route("/track/lp", methods=["OPTIONS"])
def track_lp_options():
    resp = jsonify({"ok": True})
    resp.headers["Access-Control-Allow-Origin"] = "*"
    resp.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
    resp.headers["Access-Control-Allow-Headers"] = "Content-Type"
    return resp


# ============================================================
# Agregacoes
# ============================================================
def _iter_jsonl(path: Path) -> Iterable[dict]:
    if not path.exists():
        return
    try:
        with path.open("r", encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                try:
                    yield json.loads(line)
                except Exception:
                    continue
    except Exception:
        return


def _parse_ts(ts: str) -> datetime | None:
    if not ts:
        return None
    try:
        return datetime.fromisoformat(ts.replace("Z", "+00:00"))
    except Exception:
        return None


def carregar_clicks() -> list[dict]:
    return list(_iter_jsonl(CLICKS_FILE))


def carregar_pageviews() -> list[dict]:
    return list(_iter_jsonl(PAGEVIEWS_FILE))


def agregar_clicks(clicks: list[dict]) -> dict:
    agora = datetime.now(timezone.utc)
    h24 = agora - timedelta(hours=24)
    d7 = agora - timedelta(days=7)

    total = 0
    last_24 = 0
    last_7 = 0
    por_canal: dict[str, int] = {}
    por_campanha: dict[str, int] = {}

    for c in clicks:
        total += 1
        ts = _parse_ts(c.get("ts", ""))
        if ts:
            if ts >= h24:
                last_24 += 1
            if ts >= d7:
                last_7 += 1

        src = (c.get("utm_source") or "direto").strip().lower()
        med = (c.get("utm_medium") or "-").strip().lower()
        canal = f"{src} / {med}"
        por_canal[canal] = por_canal.get(canal, 0) + 1

        camp = (c.get("utm_campaign") or "sem-campanha").strip().lower()
        por_campanha[camp] = por_campanha.get(camp, 0) + 1

    def _ranking(d: dict[str, int], key_name: str) -> list[dict]:
        if not d:
            return []
        soma = sum(d.values()) or 1
        rows = [
            {key_name: k, "qtd": v, "pct": v / soma * 100}
            for k, v in d.items()
        ]
        rows.sort(key=lambda x: -x["qtd"])
        return rows

    return {
        "total": total,
        "ultimas_24h": last_24,
        "ultimos_7d": last_7,
        "por_canal": _ranking(por_canal, "canal"),
        "por_campanha": _ranking(por_campanha, "campanha"),
    }


def agregar_pageviews(pvs: list[dict]) -> dict:
    agora = datetime.now(timezone.utc)
    h24 = agora - timedelta(hours=24)
    d7 = agora - timedelta(days=7)
    total = 0
    last_24 = 0
    last_7 = 0
    for p in pvs:
        total += 1
        ts = _parse_ts(p.get("ts", ""))
        if ts:
            if ts >= h24:
                last_24 += 1
            if ts >= d7:
                last_7 += 1
    return {
        "total": total,
        "ultimas_24h": last_24,
        "ultimos_7d": last_7,
    }
