"""
SwarmPay CLI – fast local onboarding for demo and live mode.

Usage:
    swarmpay quickstart → Create a demo-ready config
    swarmpay setup      → Interactive live configuration
    swarmpay doctor     → Check readiness
    swarmpay demo       → Run first payment demo
    swarmpay status     → Check wallet balance & network
"""
from __future__ import annotations

import os
import secrets
import sys
import webbrowser
from pathlib import Path

from swarmpay.api_server import main as run_api_server
from swarmpay.constants import SUPPORTED_NETWORKS


class Colors:
    BEE = '\033[93m'
    GREEN = '\033[92m'
    BLUE = '\033[94m'
    RESET = '\033[0m'


def print_bee(text):
    print(f"{Colors.BEE}🐝 {text}{Colors.RESET}")


def print_success(text):
    print(f"{Colors.GREEN}✓ {text}{Colors.RESET}")


def print_info(text):
    print(f"{Colors.BLUE}→ {text}{Colors.RESET}")


def print_error(text):
    print(f"❌ {text}")


def _generate_api_key() -> str:
    """Generate a persistent local API key for the REST server."""
    return "sk_swarmpay_" + secrets.token_hex(24)


def _read_env_file(env_path: Path) -> dict[str, str]:
    """Read simple KEY=VALUE pairs from .env."""
    config: dict[str, str] = {}
    if not env_path.exists():
        return config

    with open(env_path, 'r') as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#") or "=" not in line:
                continue
            key, value = line.split("=", 1)
            config[key] = value
    return config


def _with_defaults(config: dict[str, str] | None = None) -> dict[str, str]:
    """Backfill missing config values with safe local defaults."""
    merged = dict(config or {})
    defaults = {
        "CDP_API_KEY_ID": "",
        "CDP_API_KEY_SECRET": "",
        "CDP_WALLET_SECRET": "",
        "SWARMPAY_ADMIN_WALLET": "",
        "SWARMPAY_NETWORK": "base-sepolia",
        "SWARMPAY_API_KEY": _generate_api_key(),
        "SWARMPAY_HOST": "127.0.0.1",
        "SWARMPAY_PORT": "8420",
        "OPENAI_API_KEY": "",
    }
    for key, value in defaults.items():
        if key not in merged:
            merged[key] = value
    return merged


def _write_env_file(env_path: Path, config: dict[str, str]) -> None:
    """Write .env with a stable field order."""
    env_content = f"""# SwarmPay Configuration
# Generated by: swarmpay setup / swarmpay quickstart

# Coinbase Developer Platform
CDP_API_KEY_ID={config['CDP_API_KEY_ID']}
CDP_API_KEY_SECRET={config['CDP_API_KEY_SECRET']}
CDP_WALLET_SECRET={config['CDP_WALLET_SECRET']}

# SwarmPay
SWARMPAY_ADMIN_WALLET={config['SWARMPAY_ADMIN_WALLET']}
SWARMPAY_NETWORK={config['SWARMPAY_NETWORK']}
SWARMPAY_API_KEY={config['SWARMPAY_API_KEY']}
SWARMPAY_HOST={config['SWARMPAY_HOST']}
SWARMPAY_PORT={config['SWARMPAY_PORT']}

# OpenAI (optional)
OPENAI_API_KEY={config['OPENAI_API_KEY']}
"""

    fd = os.open(str(env_path), os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
    with os.fdopen(fd, 'w') as f:
        f.write(env_content)


def _ensure_gitignore_has_env() -> None:
    """Keep local secrets out of git by default."""
    gitignore_path = Path(".gitignore")
    if not gitignore_path.exists():
        return

    with open(gitignore_path, 'r') as f:
        content = f.read()
    if '.env' not in content:
        with open(gitignore_path, 'a') as f:
            f.write("\n.env\n")


def _mask_secret(value: str, keep: int = 4) -> str:
    """Mask secrets for terminal output."""
    if not value:
        return "Not set"
    if len(value) <= keep:
        return "*" * len(value)
    return f"{value[:keep]}{'*' * (len(value) - keep)}"


def _load_current_config() -> tuple[Path, dict[str, str]]:
    """Load .env and backfill defaults for missing values."""
    env_path = Path(".env")
    config = _with_defaults(_read_env_file(env_path))
    if "PAYFI_ADMIN_WALLET" in config and not config.get("SWARMPAY_ADMIN_WALLET"):
        config["SWARMPAY_ADMIN_WALLET"] = config["PAYFI_ADMIN_WALLET"]
    return env_path, config


def _inspect_config(config: dict[str, str]) -> dict[str, str | bool]:
    """Summarize whether local config is demo-ready or live-ready."""
    network = config.get("SWARMPAY_NETWORK", "base-sepolia")
    has_cdp_id = bool(config.get("CDP_API_KEY_ID"))
    has_cdp_secret = bool(config.get("CDP_API_KEY_SECRET"))
    has_wallet_secret = bool(config.get("CDP_WALLET_SECRET"))
    live_ready = has_cdp_id and has_cdp_secret

    return {
        "network": network,
        "network_supported": network in SUPPORTED_NETWORKS,
        "has_api_key": bool(config.get("SWARMPAY_API_KEY")),
        "has_admin_wallet": bool(
            config.get("SWARMPAY_ADMIN_WALLET") or config.get("PAYFI_ADMIN_WALLET")
        ),
        "has_cdp_id": has_cdp_id,
        "has_cdp_secret": has_cdp_secret,
        "has_wallet_secret": has_wallet_secret,
        "live_ready": live_ready,
        "mode": "live" if live_ready else "demo",
    }


def cmd_quickstart():
    """Create a safe local config with almost no setup friction."""
    print_bee("SwarmPay Quickstart")
    print("")
    print_info("Creating a local config for demo mode.")
    print_info("You can add Coinbase keys later when you're ready for live payments.")
    print("")

    env_path, config = _load_current_config()
    existed = env_path.exists()

    _write_env_file(env_path, config)
    _ensure_gitignore_has_env()

    print_success(".env is ready")
    if existed:
        print_info("Kept your existing values and filled in any missing defaults.")
    else:
        print_info("Created a new demo-ready config with safe defaults.")
    print("")
    print_bee("Next steps")
    print("  1. Run 'swarmpay doctor' to verify your setup")
    print("  2. Run 'swarmpay demo' to see the first payment flow")
    print("  3. Add CDP keys later to switch from demo mode to live mode")
    print("")


def cmd_setup():
    """Interactive setup wizard."""
    print_bee("Welcome to SwarmPay!")
    print("")
    print_info("Let's configure your SwarmPay instance.")
    print("")

    env_path, config = _load_current_config()
    if env_path.exists():
        print_info("Found existing .env file.")
        overwrite = input("Overwrite? (y/N): ").strip().lower()
        if overwrite != 'y':
            print_info("Keeping existing configuration.")
            return

    print("")
    print_bee("Step 1: Admin Wallet")
    print_info("This wallet receives the 1% platform fees.")
    admin_wallet = input("Admin wallet address (optional, press Enter to skip): ").strip()
    config['SWARMPAY_ADMIN_WALLET'] = admin_wallet

    print("")
    print_bee("Step 2: Choose Network")
    print("  1) Base Sepolia (Testnet) - Recommended for testing")
    print("  2) Base Mainnet")
    print("  3) Solana Devnet")
    network_choice = input("Your choice (1/2/3): ").strip()
    network_map = {'1': 'base-sepolia', '2': 'base-mainnet', '3': 'solana-devnet'}
    config['SWARMPAY_NETWORK'] = network_map.get(network_choice, 'base-sepolia')

    print("")
    print_bee("Step 3: Coinbase CDP API Keys")
    print_info("Get your keys at: https://portal.cdp.coinbase.com/api-keys")
    print("")
    open_browser = input("Open browser to CDP portal? (Y/n): ").strip().lower()
    if open_browser != 'n':
        print_info("Opening CDP portal...")
        webbrowser.open("https://portal.cdp.coinbase.com/api-keys")

    print("")
    config['CDP_API_KEY_ID'] = input("CDP API Key ID: ").strip()
    config['CDP_API_KEY_SECRET'] = input("CDP API Key Secret (paste entire key): ").strip()
    config['CDP_WALLET_SECRET'] = input("CDP Wallet Secret (optional, press Enter to skip): ").strip()

    print("")
    print_info("Writing configuration to .env...")
    _write_env_file(env_path, config)
    _ensure_gitignore_has_env()

    print_success("Configuration saved to .env")
    print("")
    print_bee("Setup complete!")
    print("")
    print_info("Next steps:")
    print("  1. Run 'swarmpay doctor' to verify live readiness")
    print("  2. Run 'swarmpay demo' to test your first payment")
    print("  3. Start the API: 'swarmpay serve'")
    print("")


def cmd_demo():
    """Run a quick payment demo."""
    print_bee("Starting SwarmPay Demo...")
    print("")

    env_path = Path(".env")
    if not env_path.exists():
        print_error("No .env file found. Run 'swarmpay quickstart' first.")
        sys.exit(1)

    print_info("Loading configuration...")
    print_success("Configuration loaded")

    print("")
    print_info("Step 1: Creating wallet for 'demo-agent'...")
    print_success("Wallet created: 0xDemoAgent123456789")

    print("")
    print_info("Step 2: Requesting test USDC from faucet...")
    print_success("Received 100 USDC (testnet)")

    print("")
    print_info("Step 3: Sending $0.50 payment...")
    print_success("Payment sent!")

    print("")
    print_bee("Payment Summary:")
    print("  ┌─────────────────────────────────┐")
    print("  │ Amount:        $0.50 USDC       │")
    print("  │ Recipient:     0xRecipient...   │")
    print("  │ Agent B gets:  $0.495 (99%)     │")
    print("  │ Platform fee:  $0.005 (1%)      │")
    print("  └─────────────────────────────────┘")

    print("")
    print_success("Payment successful!")
    print("")
    print_info("View on blockchain:")
    print("  → https://sepolia.basescan.org/tx/0xDemoTx123")
    print("")
    print_bee("That's it! Your AI agent can now pay other agents.")
    print("")
    print_info("Next steps:")
    print("  • Integrate SDK: from swarmpay import SwarmPay")
    print("  • Start API server: swarmpay serve")
    print("  • Check readiness again: swarmpay doctor")
    print("")


def cmd_status():
    """Show wallet status and balance."""
    print_bee("SwarmPay Status")
    print("")

    env_path = Path(".env")
    if not env_path.exists():
        print_error("No .env found. Run 'swarmpay quickstart' first.")
        sys.exit(1)

    _, config = _load_current_config()
    admin_wallet = config.get("SWARMPAY_ADMIN_WALLET") or config.get("PAYFI_ADMIN_WALLET", "")
    network = config.get("SWARMPAY_NETWORK", "base-sepolia")

    print_info("Configuration: OK")
    print_info(f"Network: {network}")
    print_info(f"Admin Wallet: {admin_wallet or 'Not set'}")
    print("")


def cmd_doctor():
    """Check whether the local setup is demo-ready or live-ready."""
    print_bee("SwarmPay Doctor")
    print("")

    env_path = Path(".env")
    if not env_path.exists():
        print_error("No .env found.")
        print_info("Run 'swarmpay quickstart' to create a demo-ready config.")
        sys.exit(1)

    _, config = _load_current_config()
    summary = _inspect_config(config)

    print_info(f"Mode: {summary['mode']}")
    print_info(f"Network: {summary['network']}")
    print_info(f"REST API key: {_mask_secret(config.get('SWARMPAY_API_KEY', ''))}")
    print_info(f"Admin wallet: {config.get('SWARMPAY_ADMIN_WALLET') or 'Not set'}")
    print("")

    print("Checks:")
    print(f"  {'OK' if summary['network_supported'] else 'FAIL'} supported network")
    print(f"  {'OK' if summary['has_api_key'] else 'FAIL'} persistent API key")
    print(f"  {'OK' if summary['has_cdp_id'] else 'WARN'} CDP API key id")
    print(f"  {'OK' if summary['has_cdp_secret'] else 'WARN'} CDP API key secret")
    print(f"  {'OK' if summary['has_wallet_secret'] else 'WARN'} CDP wallet secret")
    print("")

    if summary["live_ready"]:
        print_success("Live mode looks ready for real wallet operations.")
    else:
        print_info("Demo mode is ready.")
        print_info("Add CDP credentials to .env when you want live blockchain payments.")
    print("")


def cmd_escrow():
    """Manage on-chain escrows."""
    if len(sys.argv) < 3:
        print_bee("SwarmPay Escrow")
        print("")
        print("Usage: swarmpay escrow <subcommand>")
        print("")
        print("Subcommands:")
        print("  list                            → List on-chain escrow state")
        print("  fund <provider> <amount>        → Create & fund escrow")
        print("  confirm <escrow_nonce>          → Provider confirms delivery")
        print("  release <escrow_nonce>          → Buyer releases funds")
        print("  dispute <escrow_nonce> [reason] → Open dispute")
        print("  refund <escrow_nonce>           → Refund (after timeout)")
        print("")
        return

    sub = sys.argv[2]

    if sub == "list":
        _escrow_list()
    elif sub == "fund":
        if len(sys.argv) < 5:
            print_error("Usage: swarmpay escrow fund <provider_address> <amount_usd>")
            return
        _escrow_fund(sys.argv[3], float(sys.argv[4]))
    elif sub == "confirm":
        if len(sys.argv) < 4:
            print_error("Usage: swarmpay escrow confirm <escrow_nonce>")
            return
        _escrow_action("confirm", int(sys.argv[3]))
    elif sub == "release":
        if len(sys.argv) < 4:
            print_error("Usage: swarmpay escrow release <escrow_nonce>")
            return
        _escrow_action("release", int(sys.argv[3]))
    elif sub == "dispute":
        if len(sys.argv) < 4:
            print_error("Usage: swarmpay escrow dispute <escrow_nonce> [reason]")
            return
        reason = " ".join(sys.argv[4:]) if len(sys.argv) > 4 else ""
        _escrow_action("dispute", int(sys.argv[3]), reason)
    elif sub == "refund":
        if len(sys.argv) < 4:
            print_error("Usage: swarmpay escrow refund <escrow_nonce>")
            return
        _escrow_action("refund", int(sys.argv[3]))
    else:
        print_error(f"Unknown escrow subcommand: {sub}")


def _escrow_list():
    """Show escrow contract state from on-chain."""
    from swarmpay.constants import ESCROW_CONTRACTS

    print_bee("On-Chain Escrow Status")
    print("")

    for network, address in ESCROW_CONTRACTS.items():
        print_info(f"Network: {network}")
        print_info(f"Contract: {address}")

        try:
            from web3 import Web3
            import json

            rpc = "https://mainnet.base.org" if "mainnet" in network else "https://sepolia.base.org"
            w3 = Web3(Web3.HTTPProvider(rpc))

            artifacts_path = Path(__file__).parent.parent / "artifacts" / "contracts" / "SwarmpayEscrow.sol" / "SwarmPayEscrow.json"
            if artifacts_path.exists():
                with open(artifacts_path) as f:
                    abi = json.load(f)["abi"]
                contract = w3.eth.contract(address=Web3.to_checksum_address(address), abi=abi)
                next_id = contract.functions.nextEscrowId().call()
                fee_recip = contract.functions.feeRecipient().call()
                print_info(f"Next Escrow ID: {next_id}")
                print_info(f"Total Escrows: {next_id - 1}")
                print_info(f"Fee Recipient: {fee_recip}")
            else:
                print_info("(Install web3 and build artifacts for full status)")
        except ImportError:
            print_info("(Install web3 for live contract queries: pip install web3)")
        except Exception as e:
            print_error(f"Could not query contract: {e}")
        print("")


def _escrow_fund(provider: str, amount_usd: float):
    """Fund a new on-chain escrow."""
    print_bee(f"Funding escrow: ${amount_usd} → {provider[:10]}...")
    print("")
    print_error("Live escrow funding requires CDP wallet connection.")
    print_info("Use the Python SDK for programmatic escrow creation:")
    print("")
    print("  from swarmpay import SwarmPay, OnchainEscrowConfig")
    print("  sp = SwarmPay(onchain_escrow_config=OnchainEscrowConfig(...))")
    print(f"  sp.create_onchain_escrow(wallet, '{provider}', {amount_usd}, 'service')")
    print("")


def _escrow_action(action: str, escrow_nonce: int, reason: str = ""):
    """Execute an escrow action (confirm/release/dispute/refund)."""
    print_bee(f"Escrow {action}: nonce #{escrow_nonce}")
    print("")
    print_error(f"Live escrow {action} requires CDP wallet connection.")
    print_info("Use the Python SDK:")
    print("")
    if action == "confirm":
        print(f"  sp.confirm_onchain_delivery(wallet, {escrow_nonce})")
    elif action == "release":
        print(f"  sp.release_onchain_escrow(wallet, {escrow_nonce})")
    elif action == "dispute":
        print(f"  sp.dispute_onchain_escrow(wallet, {escrow_nonce}, reason='{reason}')")
    elif action == "refund":
        print(f"  sp.refund_onchain_escrow(wallet, {escrow_nonce})")
    print("")


def main():
    if len(sys.argv) < 2:
        print_bee("SwarmPay CLI")
        print("")
        print("Usage: swarmpay <command>")
        print("")
        print("Commands:")
        print("  quickstart → Create a demo-ready local config")
        print("  setup      → Interactive configuration")
        print("  doctor     → Check demo/live readiness")
        print("  demo       → Run first payment demo")
        print("  status     → Check wallet & balance")
        print("  serve      → Start API server")
        print("  escrow     → Manage on-chain escrows")
        print("")
        print("Examples:")
        print("  swarmpay quickstart")
        print("  swarmpay demo")
        print("  swarmpay escrow list")
        print("")
        return

    command = sys.argv[1]

    if command == "quickstart":
        cmd_quickstart()
    elif command == "setup":
        cmd_setup()
    elif command == "doctor":
        cmd_doctor()
    elif command == "demo":
        cmd_demo()
    elif command == "status":
        cmd_status()
    elif command == "escrow":
        cmd_escrow()
    elif command == "serve":
        print_info("Starting API server...")
        print_info("Visit: http://localhost:8420")
        run_api_server()
    else:
        print_error(f"Unknown command: {command}")
        print("Run 'swarmpay' for usage.")


if __name__ == "__main__":
    main()
