"""coworker CLI — command-line interface for the coworker protocol."""

import argparse
import base64
import json
import os
import sys
import time
from datetime import datetime, timezone
from pathlib import Path


COWORKER_DIR = Path.home() / ".coworker"
VERSION = "0.1.0"


def _config_path() -> Path:
    return COWORKER_DIR / "config.json"


def _wallet_path() -> Path:
    return COWORKER_DIR / "wallet.json"


def _peers_path() -> Path:
    return COWORKER_DIR / "peers.json"


def _load_config() -> dict:
    path = _config_path()
    if not path.exists():
        print("Not initialized. Run: coworker init")
        sys.exit(1)
    with open(path) as f:
        return json.load(f)


def _sync_wallet_address(xmtp_address: str):
    """Update config.json and wallet.json with the real XMTP address.

    The XMTP bridge derives the actual wallet address from the private key.
    This may differ from the placeholder generated by `coworker init`.
    """
    # Update config.json
    config_path = _config_path()
    if config_path.exists():
        try:
            with open(config_path) as f:
                config = json.load(f)
            if config.get("wallet") != xmtp_address:
                old = config.get("wallet", "unknown")
                config["wallet"] = xmtp_address
                with open(config_path, "w") as f:
                    json.dump(config, f, indent=2)
                print(f"  ✓ Updated config wallet: {old[:12]}... → {xmtp_address[:12]}...")
        except (json.JSONDecodeError, IOError) as e:
            print(f"  ⚠ Could not update config.json: {e}")

    # Update wallet.json
    wallet_path = _wallet_path()
    if wallet_path.exists():
        try:
            with open(wallet_path) as f:
                wallet = json.load(f)
            if wallet.get("address") != xmtp_address:
                wallet["address"] = xmtp_address
                with open(wallet_path, "w") as f:
                    json.dump(wallet, f, indent=2)
        except (json.JSONDecodeError, IOError):
            pass


# ── Commands ──────────────────────────────────────────────

def cmd_init(args):
    """Initialize a coworker agent with wallet + XMTP bridge."""
    name = args.name or "agent"
    COWORKER_DIR.mkdir(parents=True, exist_ok=True)

    config_path = _config_path()
    if config_path.exists() and not args.force:
        print(f"Already initialized. Config at {config_path}")
        print("Use --force to re-initialize.")
        return

    # Generate wallet (Ethereum-style private key + address)
    private_key = "0x" + os.urandom(32).hex()
    # Derive address from private key (simplified — just hash for now)
    import hashlib
    addr_hash = hashlib.sha256(private_key.encode()).hexdigest()[-40:]
    wallet_address = "0x" + addr_hash

    # Save config
    config = {
        "name": name,
        "wallet": wallet_address,
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    with open(config_path, "w") as f:
        json.dump(config, f, indent=2)

    # Save wallet (private key separate for security)
    wallet = {
        "private_key": private_key,
        "address": wallet_address,
        "created_at": config["created_at"],
    }
    with open(_wallet_path(), "w") as f:
        json.dump(wallet, f, indent=2)

    print(f"Initialized coworker agent: {name}")
    print(f"  Config: {config_path}")
    print(f"  Wallet: {wallet_address}")

    # Setup XMTP bridge
    print("\n  Setting up XMTP bridge...")
    try:
        from ._internal.bridge import setup_bridge, find_node
        node = find_node()
        if not node:
            print("  ⚠ Node.js >= 22 not found. Install it for XMTP networking:")
            print("    https://nodejs.org/")
            print("  (Agent can still run locally without XMTP)")
        else:
            setup_bridge(COWORKER_DIR)
            print("  ✓ XMTP bridge ready")
    except Exception as e:
        print(f"  ⚠ Bridge setup failed: {e}")
        print("  (You can set it up later with: coworker bridge setup)")

    print("\n  Next steps:")
    print("    1. Start bridge:   coworker bridge start")
    print("    2. Write your bot: python my_bot.py")
    print()
    print("  Note: Your wallet address above is a placeholder. The real XMTP")
    print("  address will be set automatically when the bridge first starts.")


def cmd_status(args):
    """Show agent status."""
    config = _load_config()
    print(f"Name:    {config['name']}")
    print(f"Wallet:  {config['wallet']}")
    print(f"Created: {config.get('created_at', 'unknown')}")

    # Peers
    peers_path = _peers_path()
    if peers_path.exists():
        try:
            with open(peers_path) as f:
                peers = json.load(f)
            print(f"Peers:   {len(peers)}")
        except (json.JSONDecodeError, IOError):
            print("Peers:   0")
    else:
        print("Peers:   0")

    # Bridge status
    from ._internal.bridge import check_running
    bridge = check_running(COWORKER_DIR)
    if bridge:
        print(f"Bridge:  ✓ running on port {bridge['port']}")
        print(f"  XMTP:  {bridge.get('address', 'unknown')[:16]}...")
    else:
        print("Bridge:  ✗ not running")


def cmd_bridge(args):
    """Manage the XMTP bridge."""
    from ._internal.bridge import start, stop, check_running, setup_bridge

    if args.action == "start":
        print("Starting XMTP bridge...")
        result = start(COWORKER_DIR, env=args.env or "dev")
        if "error" in result:
            print(f"  ✗ {result['error']}")
            if "log" in result and result["log"].strip():
                print(f"\n  Bridge log (last 500 chars):")
                for line in result["log"].strip().split("\n")[-10:]:
                    print(f"    {line}")
            sys.exit(1)
        else:
            print(f"  ✓ Bridge {result['status']} on port {result['port']}")
            xmtp_address = result.get("address", "")
            print(f"  XMTP address: {xmtp_address or 'unknown'}")

            # Sync real XMTP address back to config + wallet
            if xmtp_address:
                _sync_wallet_address(xmtp_address)

    elif args.action == "stop":
        result = stop(COWORKER_DIR)
        print(f"  Bridge: {result['status']}")

    elif args.action == "status":
        result = check_running(COWORKER_DIR)
        if result:
            print(f"  ✓ Running on port {result['port']}")
            print(f"  Address: {result.get('address', 'unknown')}")
        else:
            print("  ✗ Not running")

    elif args.action == "setup":
        try:
            setup_bridge(COWORKER_DIR)
            print("  ✓ Bridge files installed")
        except Exception as e:
            print(f"  ✗ {e}")
            sys.exit(1)


def cmd_invite(args):
    """Generate an invite code (contains wallet address for XMTP connection)."""
    config = _load_config()
    invite_data = {
        "name": config["name"],
        "wallet": config["wallet"],
        "skills": [],
        "version": VERSION,
    }
    code = base64.b64encode(json.dumps(invite_data).encode()).decode()
    print(f"Share this with your collaborator:\n")
    print(f"  coworker connect {config['wallet']}")
    print(f"\nOr full invite code:\n  {code}")


def cmd_connect(args):
    """Connect to a peer by wallet address or invite code."""
    target = args.target

    # Try as wallet address first
    if target.startswith("0x") and len(target) >= 40:
        peer_wallet = target
        peer_name = args.name or f"peer-{target[2:8]}"
        peer_data = {"wallet": peer_wallet}
    else:
        # Try as base64 invite code
        try:
            decoded = json.loads(base64.b64decode(target))
            peer_wallet = decoded["wallet"]
            peer_name = decoded.get("name", f"peer-{peer_wallet[2:8]}")
            peer_data = decoded
        except Exception:
            print("Invalid target. Provide a wallet address (0x...) or invite code.")
            sys.exit(1)

    # Save peer
    COWORKER_DIR.mkdir(parents=True, exist_ok=True)
    peers = {}
    if _peers_path().exists():
        try:
            with open(_peers_path()) as f:
                peers = json.load(f)
        except (json.JSONDecodeError, IOError):
            pass

    peers[peer_name] = {
        "wallet": peer_wallet,
        "skills": peer_data.get("skills", []),
        "version": peer_data.get("version", ""),
        "connected_at": datetime.now(timezone.utc).isoformat(),
    }

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

    print(f"Connected to: {peer_name} ({peer_wallet[:16]}...)")

    # Try XMTP discover if bridge is running
    from ._internal.bridge import check_running
    bridge = check_running(COWORKER_DIR)
    if bridge:
        print(f"  Discovering skills via XMTP...")
        try:
            from .agent import Agent
            config = _load_config()
            agent = Agent(config.get("name", "cli"), data_dir=str(COWORKER_DIR))
            # Clear stale messages and start poll loop
            import threading
            agent._running = True
            try:
                agent.client.receive(clear=True)
            except Exception:
                pass
            agent._response_box.clear()
            poll = threading.Thread(target=agent._poll_loop, daemon=True)
            poll.start()
            time.sleep(1)  # Let poll thread start consuming

            peer = agent.connect(peer_wallet, retries=2)
            agent._running = False

            if "error" not in peer:
                skills = peer.get("skills", [])
                skill_names = [s["name"] if isinstance(s, dict) else s for s in skills]
                # Update saved peer with discovered skills
                peers[peer_name]["skills"] = skills
                with open(_peers_path(), "w") as f:
                    json.dump(peers, f, indent=2)
                print(f"  ✓ Discovered {len(skills)} skills: {', '.join(skill_names)}")
            else:
                print(f"  ⚠ Discovery timed out (peer may be offline)")
                print(f"  Peer saved — skills will be discovered on next connect")
        except Exception as e:
            print(f"  ⚠ Discovery failed: {e}")
            print(f"  Peer saved — run 'coworker connect {peer_wallet}' again to retry")
    else:
        print(f"  ℹ Bridge not running — start with 'coworker bridge start' to discover skills")


def cmd_trust(args):
    """Manage peer trust tiers."""
    from ._internal.security import TrustManager, TrustTier

    config = _load_config()
    tm = TrustManager(str(COWORKER_DIR))

    TIER_NAMES = {"untrusted": 0, "known": 1, "internal": 2, "privileged": 3}

    if args.trust_action == "list":
        tiers = tm.all_tiers
        if not tiers:
            print("No trust overrides set.")
            return
        for wallet, tier_name in tiers.items():
            print(f"  {wallet}  →  {tier_name}")

    elif args.trust_action == "set":
        wallet = args.wallet
        tier_input = args.tier.lower() if args.tier else "known"
        if tier_input in TIER_NAMES:
            tier = TIER_NAMES[tier_input]
        elif tier_input.isdigit() and int(tier_input) in (0, 1, 2, 3):
            tier = int(tier_input)
        else:
            print(f"Invalid tier: {args.tier}")
            print(f"  Valid: untrusted(0), known(1), internal(2), privileged(3)")
            sys.exit(1)
        tm.set_trust_override(wallet, tier)
        label = TrustTier(tier).name.lower()
        print(f"  ✓ {wallet[:16]}... → {label}")

    elif args.trust_action == "remove":
        tm.remove_trust_override(args.wallet)
        print(f"  ✓ Removed trust override for {args.wallet[:16]}...")

    else:
        print("Usage: coworker trust {list|set|remove}")


def cmd_version(args):
    """Print version."""
    print(f"coworker-protocol {VERSION}")


# ── Main ──────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(
        prog="coworker",
        description="coworker-protocol — peer-to-peer AI agent collaboration",
    )
    sub = parser.add_subparsers(dest="command")

    # init
    p_init = sub.add_parser("init", help="Initialize agent")
    p_init.add_argument("--name", default=None, help="Agent name")
    p_init.add_argument("--force", action="store_true", help="Force re-initialization")

    # status
    sub.add_parser("status", help="Show agent status")

    # bridge
    p_bridge = sub.add_parser("bridge", help="Manage XMTP bridge")
    p_bridge.add_argument("action", choices=["start", "stop", "status", "setup"],
                          help="Bridge action")
    p_bridge.add_argument("--env", default="dev", choices=["dev", "production"],
                          help="XMTP environment")

    # invite
    sub.add_parser("invite", help="Generate invite / wallet address")

    # connect
    p_connect = sub.add_parser("connect", help="Connect to a peer")
    p_connect.add_argument("target", help="Wallet address (0x...) or invite code")
    p_connect.add_argument("--name", default=None, help="Peer name")

    # trust
    p_trust = sub.add_parser("trust", help="Manage peer trust tiers")
    trust_sub = p_trust.add_subparsers(dest="trust_action")
    trust_sub.add_parser("list", help="List all trust overrides")
    p_trust_set = trust_sub.add_parser("set", help="Set trust tier for a peer")
    p_trust_set.add_argument("wallet", help="Peer wallet address (0x...)")
    p_trust_set.add_argument("tier", help="Trust tier: untrusted/known/internal/privileged or 0-3")
    p_trust_rm = trust_sub.add_parser("remove", help="Remove trust override")
    p_trust_rm.add_argument("wallet", help="Peer wallet address (0x...)")

    # version
    sub.add_parser("version", help="Print version")

    args = parser.parse_args()

    commands = {
        "init": cmd_init,
        "status": cmd_status,
        "bridge": cmd_bridge,
        "invite": cmd_invite,
        "connect": cmd_connect,
        "trust": cmd_trust,
        "version": cmd_version,
    }

    if args.command in commands:
        commands[args.command](args)
    else:
        parser.print_help()
        sys.exit(1)


if __name__ == "__main__":
    main()
