#!/usr/bin/env python3
import importlib.util
import os
import sys
import urllib.request
from datetime import datetime, timezone
from pathlib import Path


MODULE_PATH = Path(__file__).with_name("aw-worktime-api.py")
SPEC = importlib.util.spec_from_file_location("aw_worktime_api", MODULE_PATH)
WORKTIME = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(WORKTIME)

INFLUX_URL = os.environ.get("AW_WORKTIME_INFLUX_URL", "").strip().rstrip("/")
INFLUX_ORG = os.environ.get("AW_WORKTIME_INFLUX_ORG", "proxmox").strip() or "proxmox"
INFLUX_BUCKET = os.environ.get("AW_WORKTIME_INFLUX_BUCKET", "aw_metrics").strip() or "aw_metrics"
INFLUX_TOKEN = os.environ.get("AW_WORKTIME_INFLUX_TOKEN", "").strip()
INFLUX_ENABLED = os.environ.get("AW_WORKTIME_INFLUX_ENABLED", "").strip().lower() in {"1", "true", "yes", "on"}
HOSTS = [item.strip() for item in os.environ.get("AW_WORKTIME_INFLUX_HOSTS", WORKTIME.DEFAULT_HOST).split(",") if item.strip()]
DAYS = [item.strip() for item in os.environ.get("AW_WORKTIME_INFLUX_DAYS", "today,yesterday").split(",") if item.strip()]


def _escape_tag(value):
    return (
        str(value or "")
        .replace("\\", "\\\\")
        .replace(" ", "\\ ")
        .replace(",", "\\,")
        .replace("=", "\\=")
    )


def _line(measurement, tags, fields, timestamp_ns):
    tag_part = ",".join(f"{key}={_escape_tag(value)}" for key, value in sorted(tags.items()) if value is not None and value != "")
    field_parts = []
    for key, value in fields.items():
        if isinstance(value, bool):
            field_parts.append(f"{key}={'true' if value else 'false'}")
        elif isinstance(value, int):
            field_parts.append(f"{key}={value}i")
        elif isinstance(value, float):
            field_parts.append(f"{key}={value}")
        else:
            text = str(value or "").replace("\\", "\\\\").replace('"', '\\"')
            field_parts.append(f'{key}="{text}"')
    if not field_parts:
        return ""
    if tag_part:
        return f"{measurement},{tag_part} {','.join(field_parts)} {timestamp_ns}"
    return f"{measurement} {','.join(field_parts)} {timestamp_ns}"


def _timestamp_ns(dt):
    return int(dt.astimezone(timezone.utc).timestamp() * 1_000_000_000)


def build_lines_for_day(host, report_date):
    bounds, events = WORKTIME.fetch_events_for_date(host, report_date)
    rows = WORKTIME.aggregate_rows(events, bounds["start"], bounds["end"], host)
    hourly_rows = WORKTIME.aggregate_hourly_rows(events, bounds["start"], bounds["end"], host)
    summary = WORKTIME.build_report_summary(rows)
    true_active_apps = WORKTIME.build_true_active_apps(host, report_date)

    lines = []
    daily_ts = _timestamp_ns(bounds["start"])

    for row in rows:
        lines.append(
            _line(
                "aw_rdp_worktime_daily",
                {
                    "host": host,
                    "user": row["user"],
                    "user_id": row["user_id"],
                    "report_date": report_date.isoformat(),
                },
                {
                    "active_seconds": int(row["active_seconds"]),
                    "idle_seconds": int(row["idle_seconds"]),
                    "sessions_count": int(row["sessions_count"]),
                    "samples_count": int(row["samples_count"]),
                    "active_samples": int(row["active_samples"]),
                },
                daily_ts,
            )
        )

    for row in hourly_rows:
        lines.append(
            _line(
                "aw_rdp_worktime_hourly",
                {
                    "host": host,
                    "user": row["user"],
                    "user_id": row["user_id"],
                    "report_date": row["report_date"],
                    "hour_local": row["hour_local"],
                },
                {
                    "active_seconds": int(row["active_seconds"]),
                },
                _timestamp_ns(WORKTIME.pts(row["bucket_start_utc"])),
            )
        )

    lines.append(
        _line(
            "aw_rdp_worktime_summary_daily",
            {
                "host": host,
                "report_date": report_date.isoformat(),
            },
            {
                "users_count": int(summary["users_count"]),
                "total_active_seconds": int(summary["total_active_seconds"]),
                "top_user": summary["top_user"],
            },
            daily_ts,
        )
    )

    for app in true_active_apps:
        lines.append(
            _line(
                "aw_true_active_app_daily",
                {
                    "host": host,
                    "application": app["application"],
                    "report_date": report_date.isoformat(),
                },
                {
                    "proved_work_seconds": int(app.get("proved_work_seconds", 0) or 0),
                    "evidence_events": int(app.get("evidence_events", 0) or 0),
                    "proved_work_human": app.get("proved_work_human", ""),
                    "proved_work_hhmm": app.get("proved_work_hhmm", ""),
                    "last_action": app.get("last_action", ""),
                    "last_action_local": app.get("last_action_local", ""),
                    "last_action_utc": app.get("last_action_utc", ""),
                },
                daily_ts,
            )
        )
    return [line for line in lines if line]


def write_lines(lines):
    if not lines:
        return 0
    if not INFLUX_URL or not INFLUX_TOKEN:
        raise RuntimeError("InfluxDB destination is not configured")
    payload = ("\n".join(lines) + "\n").encode("utf-8")
    req = urllib.request.Request(
        f"{INFLUX_URL}/api/v2/write?org={INFLUX_ORG}&bucket={INFLUX_BUCKET}&precision=ns",
        data=payload,
        method="POST",
        headers={"Authorization": f"Token {INFLUX_TOKEN}", "Content-Type": "text/plain; charset=utf-8"},
    )
    with urllib.request.urlopen(req, timeout=30) as response:
        if response.status not in {204, 200}:
            raise RuntimeError(f"InfluxDB write failed with status={response.status}")
    return len(lines)


def main():
    if not INFLUX_ENABLED:
        print("[aw-worktime-influx-exporter] disabled by AW_WORKTIME_INFLUX_ENABLED", file=sys.stderr)
        return 0

    lines = []
    for host in HOSTS:
        for day in DAYS:
            report_date = WORKTIME.resolve_report_date(day=day)
            lines.extend(build_lines_for_day(host, report_date))
    written = write_lines(lines)
    print(f"[aw-worktime-influx-exporter] wrote {written} points to {INFLUX_BUCKET}", file=sys.stderr)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
