#!/usr/bin/env python3
"""
ClawMail Setup Script

One-step setup for ClawMail: generates system ID, registers, and creates inbox.

Usage:
    python setup.py my-agent@clawmail.cc
    python setup.py my-agent              # @clawmail.cc is optional
"""

import hashlib
import json
import os
import re
import socket
import getpass
import sys
import urllib.request
import urllib.error
from pathlib import Path

# Configuration
CLAWMAIL_DIR = Path.home() / ".clawmail"
SYSTEM_ID_FILE = CLAWMAIL_DIR / "system_id"
CONFIG_FILE = CLAWMAIL_DIR / "config.json"
API_URL = os.environ.get("CLAWMAIL_API_URL", "https://api.clawmail.cc")

# Colors for terminal output
class Colors:
    RED = "\033[0;31m"
    GREEN = "\033[0;32m"
    YELLOW = "\033[1;33m"
    BLUE = "\033[0;34m"
    CYAN = "\033[0;36m"
    NC = "\033[0m"  # No Color

    @classmethod
    def disable(cls):
        cls.RED = cls.GREEN = cls.YELLOW = cls.BLUE = cls.CYAN = cls.NC = ""


# Disable colors if not a TTY
if not sys.stdout.isatty():
    Colors.disable()


def print_error(msg: str):
    print(f"{Colors.RED}Error: {msg}{Colors.NC}")


def print_success(msg: str):
    print(f"{Colors.GREEN}{msg}{Colors.NC}")


def print_info(msg: str):
    print(f"{Colors.BLUE}{msg}{Colors.NC}")


def print_warn(msg: str):
    print(f"{Colors.YELLOW}{msg}{Colors.NC}")


def get_machine_fingerprint() -> str:
    """Generate a fingerprint based on stable machine characteristics."""
    parts = [
        socket.gethostname(),
        getpass.getuser(),
        str(Path.home()),
    ]

    # Add machine ID if available (Linux)
    machine_id_paths = [
        "/etc/machine-id",
        "/var/lib/dbus/machine-id",
    ]

    for path in machine_id_paths:
        try:
            with open(path, "r") as f:
                machine_id = f.read().strip()
                if machine_id:
                    parts.append(machine_id)
                    break
        except (FileNotFoundError, PermissionError):
            continue

    # On macOS, try to get hardware UUID
    if sys.platform == "darwin":
        try:
            import subprocess

            result = subprocess.run(
                ["ioreg", "-rd1", "-c", "IOPlatformExpertDevice"],
                capture_output=True,
                text=True,
            )
            for line in result.stdout.split("\n"):
                if "IOPlatformUUID" in line:
                    uuid = line.split('"')[-2]
                    parts.append(uuid)
                    break
        except Exception:
            pass

    return "|".join(parts)


def generate_system_id() -> str:
    """Generate a system ID from machine fingerprint."""
    fingerprint = get_machine_fingerprint()
    hash_obj = hashlib.sha256(fingerprint.encode("utf-8"))
    return f"clw_{hash_obj.hexdigest()[:32]}"


def ensure_clawmail_dir():
    """Ensure the .clawmail directory exists."""
    CLAWMAIL_DIR.mkdir(parents=True, exist_ok=True)


def get_or_create_system_id() -> tuple[str, bool]:
    """Get existing system ID or create a new one."""
    if SYSTEM_ID_FILE.exists():
        try:
            stored_id = SYSTEM_ID_FILE.read_text().strip()
            if stored_id:
                return stored_id, False
        except Exception:
            pass

    # Generate new ID
    new_id = generate_system_id()
    ensure_clawmail_dir()
    SYSTEM_ID_FILE.write_text(new_id + "\n")
    SYSTEM_ID_FILE.chmod(0o600)
    return new_id, True


def load_config() -> dict:
    """Load existing config if present."""
    if CONFIG_FILE.exists():
        try:
            return json.loads(CONFIG_FILE.read_text())
        except Exception:
            pass
    return {}


def save_config(config: dict):
    """Save config to disk."""
    ensure_clawmail_dir()
    CONFIG_FILE.write_text(json.dumps(config, indent=2) + "\n")
    CONFIG_FILE.chmod(0o600)


def api_request(method: str, endpoint: str, data: dict = None, system_id: str = None) -> dict:
    """Make an API request."""
    url = f"{API_URL}{endpoint}"
    headers = {"Content-Type": "application/json"}

    if system_id:
        headers["X-System-ID"] = system_id

    body = json.dumps(data).encode("utf-8") if data else None

    req = urllib.request.Request(url, data=body, headers=headers, method=method)

    try:
        with urllib.request.urlopen(req, timeout=30) as response:
            return json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        error_body = e.read().decode("utf-8")
        try:
            return json.loads(error_body)
        except json.JSONDecodeError:
            return {"error": error_body, "status": e.code}
    except urllib.error.URLError as e:
        return {"error": f"Connection failed: {e.reason}"}
    except Exception as e:
        return {"error": str(e)}


def parse_email(email_arg: str) -> str:
    """Parse email argument and extract username."""
    email_arg = email_arg.strip().lower()

    # Remove @clawmail.cc suffix if present
    if email_arg.endswith("@clawmail.cc"):
        username = email_arg[:-12]
    else:
        username = email_arg

    # Validate username
    if not re.match(r"^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$", username) or len(username) < 2:
        print_error(f"Invalid username: {username}")
        print("Username must:")
        print("  - Be 2+ characters")
        print("  - Start and end with a letter or number")
        print("  - Only contain letters, numbers, dots, hyphens, underscores")
        sys.exit(1)

    return username


def main():
    if len(sys.argv) < 2:
        print("Usage: python setup.py <email>")
        print("")
        print("Examples:")
        print("  python setup.py my-agent@clawmail.cc")
        print("  python setup.py my-agent")
        sys.exit(1)

    username = parse_email(sys.argv[1])
    email = f"{username}@clawmail.cc"

    print(f"{Colors.CYAN}ClawMail Setup{Colors.NC}")
    print("=" * 40)
    print("")

    # Step 1: Get or create system ID
    print_info("Generating system ID...")
    system_id, is_new_id = get_or_create_system_id()

    if is_new_id:
        print_success(f"Created system ID: {system_id}")
    else:
        print(f"Using existing system ID: {system_id}")

    # Step 2: Register with API
    print("")
    print_info("Registering with ClawMail...")

    auth_response = api_request("POST", "/v1/auth/identify", {"system_id": system_id})

    if "error" in auth_response:
        print_error(f"Failed to register: {auth_response.get('error')}")
        sys.exit(1)

    is_new_user = auth_response.get("is_new_user", False)
    user_id = auth_response.get("user_id", "")

    if is_new_user:
        print_success("Created new ClawMail account!")
    else:
        print("Logged into existing account.")

    # Step 3: Check if user already has an inbox
    print("")
    print_info("Setting up inbox...")

    config = load_config()

    # Try to list existing inboxes first
    list_response = api_request("GET", "/v1/inboxes", system_id=system_id)

    existing_inbox = None
    if isinstance(list_response.get("inboxes"), list):
        for inbox in list_response["inboxes"]:
            if inbox.get("address") == email:
                existing_inbox = inbox
                break

        # Check if user already has an inbox (one per system for free tier)
        if not existing_inbox and list_response["inboxes"]:
            existing = list_response["inboxes"][0]
            print_warn(f"You already have an inbox: {existing['address']}")
            print_warn("Free tier is limited to one inbox per system.")
            print("")
            print("Your existing inbox details:")
            print(f"  Email:    {existing['address']}")
            print(f"  Inbox ID: {existing['id']}")
            print("")
            print("To upgrade for multiple inboxes, visit: https://clawmail.cc/upgrade")

            # Save existing config
            config["system_id"] = system_id
            config["inbox_id"] = existing["id"]
            config["email"] = existing["address"]
            save_config(config)
            return

    if existing_inbox:
        print(f"Inbox already exists: {email}")
        inbox_id = existing_inbox["id"]
    else:
        # Create new inbox
        create_response = api_request(
            "POST", "/v1/inboxes", {"username": username}, system_id=system_id
        )

        if "error" in create_response:
            error_msg = create_response.get("error", "Unknown error")
            if "already taken" in error_msg.lower() or "already exists" in error_msg.lower():
                print_error(f"Username '{username}' is already taken. Try a different one.")
            else:
                print_error(f"Failed to create inbox: {error_msg}")
            sys.exit(1)

        inbox_id = create_response.get("id", create_response.get("inbox_id", ""))
        print_success(f"Created inbox: {email}")

    # Save config
    config["system_id"] = system_id
    config["inbox_id"] = inbox_id
    config["email"] = email
    save_config(config)

    # Success!
    print("")
    print("=" * 40)
    print_success("Setup complete!")
    print("=" * 40)
    print("")
    print(f"  Email:     {Colors.CYAN}{email}{Colors.NC}")
    print(f"  Inbox ID:  {inbox_id}")
    print(f"  System ID: {system_id}")
    print("")
    print(f"Config saved to: {CONFIG_FILE}")
    print("")
    print("Quick start:")
    print(f"  # Poll for new emails")
    print(f"  curl {API_URL}/v1/inboxes/{inbox_id}/poll \\")
    print(f"    -H 'X-System-ID: {system_id}'")
    print("")
    print(f"  # Send an email")
    print(f"  curl -X POST {API_URL}/v1/inboxes/{inbox_id}/messages \\")
    print(f"    -H 'X-System-ID: {system_id}' \\")
    print(f"    -H 'Content-Type: application/json' \\")
    print(f"    -d '{{\"to\": \"user@example.com\", \"subject\": \"Hello\", \"body\": \"Hi there!\"}}'")


if __name__ == "__main__":
    main()
