#!/usr/bin/env python3
"""
get_mesh_auth.py — OAuth-First Auth Key Collection for Jetson Orin Nano

Generates a manifest.json identity card for the Jetson:
- Opens Tailscale auth key generation page
- Prompts user to paste auth key
- Generates manifest with worker_id, hub_address, timestamps
- Stores manifest in ~/.engram/manifest.json
- Exports TAILSCALE_AUTHKEY to .env.tailscale for deploy_to_node.sh
"""

import json
import os
import subprocess
import sys
import uuid
from datetime import datetime
from pathlib import Path


def get_tailscale_magicsdns():
    """Fetch the Ryzen's Tailscale MagicDNS name."""
    try:
        result = subprocess.run(["tailscale", "status", "--json"], capture_output=True, text=True, timeout=5)
        if result.returncode == 0:
            status = json.loads(result.stdout)
            # Extract local node's DNS name
            if "Self" in status:
                self_node = status["Self"]
                dns_name = self_node.get("DNSName", "").rstrip(".")
                if dns_name:
                    return dns_name
    except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError):
        pass

    return None


def open_tailscale_authkey_page():
    """Open Tailscale auth key generation page in browser."""
    url = "https://login.tailscale.com/admin/authkeys"

    try:
        subprocess.run(["xdg-open", url], capture_output=True, timeout=3)
        print(f"\n✓ Opened {url} in your browser")
    except (FileNotFoundError, subprocess.TimeoutExpired):
        print("\n⚠ Could not open browser automatically.")
        print(f"Please visit: {url}")


def validate_auth_key(key: str) -> bool:
    """Basic validation of Tailscale auth key format."""
    # Tailscale auth keys are typically 40-50 character alphanumeric strings
    key = key.strip()
    if len(key) < 30:
        return False
    if not key.replace("-", "").replace("_", "").isalnum():
        return False
    return True


def generate_manifest(auth_key: str, worker_id: str = None, hub_address: str = None) -> dict:
    """Generate the manifest.json identity card."""
    if not worker_id:
        worker_id = f"jetson-{uuid.uuid4().hex[:8]}"

    if not hub_address:
        hub_address = get_tailscale_magicsdns()
        if not hub_address:
            hub_address = "ryzen.tailnet-name.ts.net"  # Fallback

    manifest = {
        "tailscale_auth_key": auth_key,
        "worker_id": worker_id,
        "hub_address": hub_address,
        "provision_date": datetime.utcnow().isoformat() + "Z",
        "hardware_tier": "orin-nano",
    }

    return manifest


def main():
    print("\n" + "=" * 70)
    print("  Engram Fleet Onboarding — OAuth Auth Key Collection")
    print("=" * 70 + "\n")

    # Step 1: Open browser
    print("📖 Step 1: Generate Tailscale Auth Key")
    print("-" * 70)
    open_tailscale_authkey_page()
    input("\nPress Enter once you have copied your auth key...")

    # Step 2: Collect auth key
    print("\n📝 Step 2: Paste Your Auth Key")
    print("-" * 70)
    while True:
        auth_key = input("Paste your Tailscale auth key: ").strip()

        if not auth_key:
            print("❌ Auth key cannot be empty")
            continue

        if not validate_auth_key(auth_key):
            print("❌ Auth key format looks invalid. Please try again.")
            continue

        print(f"✓ Auth key accepted ({len(auth_key)} chars)")
        break

    # Step 3: Get Ryzen's Tailscale info
    print("\n🔍 Step 3: Detecting Your Ryzen's Tailscale Configuration")
    print("-" * 70)
    hub_address = get_tailscale_magicsdns()
    if hub_address:
        print(f"✓ Detected hub address: {hub_address}")
    else:
        print("⚠ Could not auto-detect hub address (will use fallback)")
        hub_address = None

    # Step 4: Generate worker ID
    print("\n🆔 Step 4: Generate Worker Identity")
    print("-" * 70)
    worker_id = f"jetson-{uuid.uuid4().hex[:8]}"
    print(f"Generated worker_id: {worker_id}")

    # Step 5: Create manifest
    print("\n📋 Step 5: Creating Manifest")
    print("-" * 70)
    manifest = generate_manifest(auth_key, worker_id, hub_address)

    # Step 6: Save manifest to ~/.engram/manifest.json
    manifest_path = Path.home() / ".engram" / "manifest.json"
    manifest_path.parent.mkdir(parents=True, exist_ok=True)

    with open(manifest_path, "w") as f:
        json.dump(manifest, f, indent=2)

    # Make readable only by user (security)
    os.chmod(manifest_path, 0o600)

    print(f"✓ Manifest saved to: {manifest_path}")
    print(f"  Worker ID: {manifest['worker_id']}")
    print(f"  Hub Address: {manifest['hub_address']}")
    print(f"  Hardware Tier: {manifest['hardware_tier']}")

    # Step 7: Export to .env.tailscale for deploy script
    print("\n🔐 Step 6: Exporting Auth Key for Deployment")
    print("-" * 70)
    env_file = Path.home() / "engram" / ".env.tailscale"
    env_file.parent.mkdir(parents=True, exist_ok=True)

    with open(env_file, "w") as f:
        f.write(f"TAILSCALE_AUTHKEY={auth_key}\n")

    os.chmod(env_file, 0o600)
    print(f"✓ Auth key exported to: {env_file}")

    print("\n" + "=" * 70)
    print("✅ Ready for Deployment")
    print("=" * 70)
    print("\nNext: Run the following to deploy to your Jetson:")
    print("  cd ~/engram && bash scripts/deploy_to_node.sh")
    print("\n")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\n⚠ Cancelled by user")
        sys.exit(1)
    except Exception as e:
        print(f"\n❌ Error: {e}", file=sys.stderr)
        sys.exit(1)
