#!/usr/bin/env python3
"""
resign_historical_telemetry.py - Wellbeing Historical Nostr Telemetry Resigner & Importer

Migrates legacy telemetry events (Kinds 30078, 30342, 30343, 30344, 34557, 30345)
into canonical SNIP-10 regular and replaceable event kinds (1359, 1342, 10343, 1343, 1357, 1345, 1073).
Preserves historical created_at timestamps and resigns using 'nak event'.
"""

import argparse
import json
import os
import subprocess
import sys
from datetime import datetime
from typing import Dict, List, Optional, Tuple


def parse_args():
    parser = argparse.ArgumentParser(description="Resign and migrate legacy Wellbeing telemetry events to canonical SNIP-10 kinds.")
    parser.add_argument("--input", "-i", help="Path to input .jsonl file containing legacy events.")
    parser.add_argument("--sec", "-s", default=os.getenv("NOSTR_SECRET_KEY", ""), help="Nostr secret key (hex or nsec) for signing.")
    parser.add_argument("--output", "-o", help="Path to write migrated signed events (.jsonl).")
    parser.add_argument("--publish-relay", "-p", action="append", default=[], help="Relay WebSocket URL to publish resigned events to.")
    parser.add_argument("--dry-run", action="store_true", help="Perform conversion and display mapping without signing or publishing.")
    parser.add_argument("--verbose", "-v", action="store_true", help="Print verbose details for every converted event.")
    return parser.parse_args()


def extract_date_tag(event: dict) -> Optional[str]:
    """Extract YYYY-MM-DD from tags or created_at."""
    for tag in event.get("tags", []):
        if len(tag) >= 2:
            if tag[0] == "timestamp":
                return tag[1].strip()
            elif tag[0] == "d":
                val = tag[1]
                for prefix in ("holyfit:", "nunlock:", "cell-ibacy:", "cellibacy:", "thehabit:", "sistercharge:"):
                    val = val.replace(prefix, "")
                if len(val) == 10 and val.count("-") == 2:
                    return val
    ts = event.get("created_at")
    if ts:
        return datetime.fromtimestamp(ts).strftime("%Y-%m-%d")
    return None


def convert_event(event: dict) -> Optional[Tuple[int, List[List[str]], str, int]]:
    """
    Map legacy event to (canonical_kind, tags, content, created_at).
    Returns None if event cannot be converted or is already canonical.
    """
    kind = event.get("kind")
    content = event.get("content", "")
    created_at = event.get("created_at", int(datetime.now().timestamp()))
    tags = event.get("tags", [])
    tag_map = {t[0]: t[1] for t in tags if len(t) >= 2}

    date_str = extract_date_tag(event) or datetime.fromtimestamp(created_at).strftime("%Y-%m-%d")

    # 1. Holy Fit (Steps)
    if kind == 30078 and any("holyfit" in t[1].lower() for t in tags if len(t) >= 2 and t[0] in ("d", "t", "client")):
        canonical_kind = 1359
        new_tags = [
            ["unit", "steps"],
            ["t", "health"],
            ["t", "step_count"],
            ["period", "daily"],
            ["timestamp", date_str],
            ["source", "Holy Fit"]
        ]
        return canonical_kind, new_tags, content, created_at

    # 2. Nunlock (Device Unlocks)
    if kind in (30342, 30078) and any("nunlock" in t[1].lower() for t in tags if len(t) >= 2 and t[0] in ("d", "t", "client")):
        canonical_kind = 1342
        new_tags = [
            ["timestamp", date_str]
        ]
        return canonical_kind, new_tags, content, created_at

    # 3. Sister Charge (Battery Status & Logs)
    if kind in (30343, 30078) and any("sistercharge" in t[1].lower() for t in tags if len(t) >= 2 and t[0] in ("d", "t", "client")):
        canonical_kind = 1343  # Regular telemetry log
        new_tags = [
            ["timestamp", date_str]
        ]
        # Copy battery tags if present
        for t in tags:
            if len(t) >= 2 and t[0] in ("level", "voltage", "temp_c", "charging"):
                new_tags.append([t[0], t[1]])
        return canonical_kind, new_tags, content, created_at

    # 4. Cell-ibacy (Network Usage)
    if kind in (34557, 30078) and any("cell" in t[1].lower() for t in tags if len(t) >= 2 and t[0] in ("d", "t", "client")):
        canonical_kind = 1357
        new_tags = [
            ["timestamp", date_str],
            ["alt", "Daily Network Usage Telemetry"]
        ]
        return canonical_kind, new_tags, content, created_at

    # 5. The Habit (App Screen Time)
    if kind in (30345, 30078) and any("thehabit" in t[1].lower() for t in tags if len(t) >= 2 and t[0] in ("d", "t", "client")):
        canonical_kind = 1345
        new_tags = [
            ["timestamp", date_str],
            ["alt", "Daily App Usage Summary"]
        ]
        return canonical_kind, new_tags, content, created_at

    # 6. Saint Stream (Media Scrobble Archive)
    if kind in (30344, 30078) and any("music" in t[1].lower() or "saintstream" in t[1].lower() for t in tags if len(t) >= 2):
        canonical_kind = 1073
        new_tags = []
        for t in tags:
            if len(t) >= 2 and t[0] in ("title", "artist", "duration"):
                new_tags.append([t[0], t[1]])
        if not any(t[0] == "title" for t in new_tags):
            if " by " in content:
                parts = content.split(" by ", 1)
                new_tags.append(["title", parts[0].strip()])
                new_tags.append(["artist", parts[1].strip()])
        return canonical_kind, new_tags, content, created_at

    return None


def sign_event_with_nak(sec_key: str, kind: int, tags: List[List[str]], content: str, created_at: int, publish_relays: List[str]) -> Optional[dict]:
    """Construct, sign, and optionally publish an event using 'nak event'."""
    cmd = [
        "nak", "event",
        "--sec", sec_key,
        "--created-at", str(created_at),
        "-k", str(kind),
        "-c", content,
    ]
    for tag in tags:
        if len(tag) >= 2:
            cmd.extend(["-t", f"{tag[0]}={tag[1]}"])

    if publish_relays:
        cmd.extend(publish_relays)

    try:
        res = subprocess.run(cmd, capture_output=True, text=True, check=True)
        # Parse stdout JSON
        for line in res.stdout.splitlines():
            line = line.strip()
            if line.startswith("{") and line.endswith("}"):
                return json.loads(line)
    except subprocess.CalledProcessError as e:
        print(f"Error signing event with nak: {e.stderr}", file=sys.stderr)
    except Exception as e:
        print(f"Exception signing event: {e}", file=sys.stderr)
    return None


def main():
    args = parse_args()

    if not args.input:
        print("Error: --input <path_to_jsonl> is required.", file=sys.stderr)
        sys.exit(1)

    if not os.path.exists(args.input):
        print(f"Error: Input file '{args.input}' not found.", file=sys.stderr)
        sys.exit(1)

    if not args.dry_run and not args.sec:
        print("Error: Nostr secret key (--sec or NOSTR_SECRET_KEY) required to sign events.", file=sys.stderr)
        sys.exit(1)

    print(f"🔄 Scanning and resigning events from {args.input}...")
    if args.dry_run:
        print("⚠️  DRY-RUN MODE ACTIVE: No signatures created, no events published.")

    converted_count = 0
    skipped_count = 0
    out_file = open(args.output, "w") if args.output else None

    try:
        with open(args.input, "r") as f:
            for idx, line in enumerate(f, 1):
                line = line.strip()
                if not line:
                    continue
                try:
                    event = json.loads(line)
                except Exception:
                    continue

                conversion = convert_event(event)
                if not conversion:
                    skipped_count += 1
                    continue

                canonical_kind, new_tags, content, created_at = conversion
                old_kind = event.get("kind")

                if args.verbose or args.dry_run:
                    date_val = next((t[1] for t in new_tags if t[0] == "timestamp"), "N/A")
                    print(f"  [{idx}] Converted Kind {old_kind} -> Kind {canonical_kind} (Date: {date_val}, CreatedAt: {created_at})")

                if args.dry_run:
                    converted_count += 1
                    continue

                # Sign using nak
                signed_event = sign_event_with_nak(args.sec, canonical_kind, new_tags, content, created_at, args.publish_relay)
                if signed_event:
                    converted_count += 1
                    if out_file:
                        out_file.write(json.dumps(signed_event) + "\n")
                else:
                    print(f"  ❌ Failed to sign event index {idx} (Kind {canonical_kind})", file=sys.stderr)

    finally:
        if out_file:
            out_file.close()

    print("\n✅ Resigning Complete!")
    print(f"  Total Converted & Processed: {converted_count}")
    print(f"  Total Skipped / Non-Legacy:  {skipped_count}")
    if args.output:
        print(f"  Output saved to: {args.output}")
    if args.publish_relay:
        print(f"  Published to relays: {', '.join(args.publish_relay)}")


if __name__ == "__main__":
    main()
