# (c) cavaliba.com - data - views_telemetry.py

"""
Telemetry UI: landing page (key/function/period selector, dashboards, raw events),
predefined dashboards, and the HTMX widget snippet both pages load. p_telemetry_read.

Views: index, dashboard, widget
"""

import uuid
from urllib.parse import urlencode

from django.contrib import messages
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.utils import timezone
from django.utils.translation import gettext as _

from app_data.aaa import start_view
from app_data.telemetry import (
    DASHBOARDS,
    PERIODS,
    RAW_DEFAULT_LIMIT,
    WIDGETS,
    TelemetryError,
    get_key_detail,
    get_keys,
    get_raw,
    widget_data,
    widget_spec,
)
from app_home.log import log2

INDEX_DEFAULT_START = "now-1d"
INDEX_DEFAULT_END = "now"


def _widget_entry(entry):
    """Return {w, query} for a dashboard entry: a WIDGETS name or an inline spec dict."""

    if isinstance(entry, str):
        return {"w": WIDGETS.get(entry, {}).get("w", "value"), "query": urlencode({"name": entry})}
    return {"w": entry.get("w", "value"), "query": urlencode(entry)}


def _raw_lines(events):
    """Format raw events as fixed-width text lines."""

    lines = []
    for ev in events:
        value = ev["svalue"] or f"{ev['value']:g}"
        did = f" id={ev['distinct_id']}" if ev["distinct_id"] else ""
        lines.append(
            f"{timezone.localtime(ev['timestamp']):%Y-%m-%d %H:%M:%S}  {ev['type']:<9}  {ev['key']}{did}  {value}"
        )
    return lines


# ------------------------------------------------------------------
# GET /telemetry/
# ------------------------------------------------------------------


def index(request):
    """Landing page: key/function/period/id/range selector rendering a barchart and a
    table, list of dashboards, last N raw events."""

    context = start_view(
        request,
        app="data",
        view="telemetry_index",
        perm="p_telemetry_read",
        noauthz="app_home:private",
    )
    if context["redirect"]:
        return redirect(context["redirect"])

    params = {k: request.GET.get(k, "").strip() for k in ("key", "function", "period", "id")}
    params["start"] = request.GET.get("start", "").strip() or INDEX_DEFAULT_START
    params["end"] = request.GET.get("end", "").strip() or INDEX_DEFAULT_END

    detail = None
    widgets = []
    if params["key"]:
        try:
            detail = get_key_detail(params["key"])
        except TelemetryError as e:
            messages.add_message(request, messages.ERROR, str(e))

    if detail:
        if params["function"] not in detail["functions"]:
            params["function"] = detail["default_function"]
        if params["period"] not in detail["periods"]:
            params["period"] = "hour" if "hour" in detail["periods"] else detail["periods"][0]
        if params["id"] not in detail["ids"]:
            params["id"] = ""
        spec = {k: v for k, v in params.items() if v}
        widgets = [_widget_entry(dict(spec, w="barchart")), _widget_entry(dict(spec, w="table"))]
        # per-id breakdown, when the key has ids and the function can be combined
        if detail["ids"] and params["function"] not in ("breakdown", "buckets", "distinct"):
            widgets.append(_widget_entry(dict(spec, w="idtable", id="")))

    try:
        raw_limit = int(request.GET.get("raw", RAW_DEFAULT_LIMIT))
    except ValueError:
        raw_limit = RAW_DEFAULT_LIMIT

    log2.access("telemetry.index", extra={"key": params["key"]})

    context["keys"] = get_keys()
    context["detail"] = detail
    context["params"] = params
    context["periods"] = detail["periods"] if detail else PERIODS
    context["widgets"] = widgets
    context["dashboards"] = DASHBOARDS
    context["raw_limit"] = raw_limit
    context["raw_lines"] = _raw_lines(get_raw(raw_limit, params["key"] or None))
    return render(request, "app_data/telemetry/index.html", context)


# ------------------------------------------------------------------
# GET /telemetry/dashboard/<name>/
# ------------------------------------------------------------------


def dashboard(request, name):
    """Predefined dashboard: a grid of widgets, each loaded and refreshed by HTMX."""

    context = start_view(
        request,
        app="data",
        view="telemetry_dashboard",
        perm="p_telemetry_read",
        noauthz="app_home:private",
    )
    if context["redirect"]:
        return redirect(context["redirect"])

    board = DASHBOARDS.get(name)
    if not board:
        messages.add_message(request, messages.ERROR, _("Unknown dashboard: ") + name)
        return redirect("telemetry:index")

    log2.access("telemetry.dashboard", target=("dashboard", name))

    context["name"] = name
    context["board"] = board
    context["dashboards"] = DASHBOARDS
    context["widgets"] = [_widget_entry(entry) for entry in board["widgets"]]
    return render(request, "app_data/telemetry/dashboard.html", context)


# ------------------------------------------------------------------
# GET /telemetry/widget/?name=... | ?w=&key=&function=&period=&id=&at=&start=&end=
# ------------------------------------------------------------------


def widget(request):
    """HTMX snippet: one widget (value card, table or barchart); errors render inline."""

    context = start_view(
        request,
        app="data",
        view="telemetry_widget",
        perm="p_telemetry_read",
        noauthz="app_home:private",
    )
    if context["redirect"]:
        return HttpResponse("")

    try:
        data = widget_data(widget_spec(request.GET))
    except TelemetryError as e:
        return render(request, "app_data/telemetry/_widget_error.html", {"error": str(e)})

    data["uid"] = "tw-" + uuid.uuid4().hex[:8]
    return render(request, f"app_data/telemetry/_widget_{data['w']}.html", {"widget": data})
