"""
Nexa Language — nexa deploy command (Phase 7 / v27)
One-command deployment to Vercel, Railway, and Hugging Face Spaces.

Usage:
    nexa deploy --target vercel    # deploy web app to Vercel
    nexa deploy --target railway   # deploy API server to Railway
    nexa deploy --target hf        # deploy ML model to Hugging Face Spaces
    nexa deploy --target fly       # deploy to Fly.io (Docker)
    nexa deploy --dry-run          # preview what would be deployed
"""
from __future__ import annotations
import os, sys, json, subprocess, shutil
from pathlib import Path


def _check_nexa_json() -> dict:
    """Load and validate nexa.json in the current directory."""
    p = Path("nexa.json")
    if not p.exists():
        print("  ❌ No nexa.json found. Run: nexa new <name> to scaffold a project.")
        sys.exit(1)
    return json.loads(p.read_text(encoding="utf-8"))


def _run(cmd: str, dry_run: bool = False) -> int:
    """Print and optionally run a shell command."""
    print(f"  $ {cmd}")
    if dry_run:
        return 0
    return subprocess.call(cmd, shell=True)


# ── Deploy targets ────────────────────────────────────────────────────────────

def deploy_vercel(meta: dict, dry_run: bool = False):
    """Deploy a Nexa web project to Vercel."""
    name = meta.get("name", "nexa-app")
    print(f"\n  🚀 Deploying '{name}' to Vercel...")

    if not shutil.which("vercel"):
        print("  ⚠️  Vercel CLI not found. Installing...")
        _run("npm install -g vercel", dry_run=dry_run)

    # Build if needed
    if Path("main.nexa").exists():
        print("  📦 Compiling main.nexa → Python (for serverless functions)...")
        _run("python -m nexa_lang compile main.nexa", dry_run=dry_run)

    # Generate vercel.json
    vercel_config = {
        "name": name,
        "version": 2,
        "builds": [{"src": "*.py", "use": "@vercel/python"}],
        "routes": [{"src": "/(.*)", "dest": "main.py"}]
    }
    if not dry_run:
        Path("vercel.json").write_text(json.dumps(vercel_config, indent=2), encoding="utf-8")
        print("  ✅ Generated vercel.json")

    rc = _run("vercel --prod", dry_run=dry_run)
    if rc == 0 and not dry_run:
        print(f"\n  ✅ Deployed! Your app is live at: https://{name}.vercel.app")
    return rc


def deploy_railway(meta: dict, dry_run: bool = False):
    """Deploy a Nexa API server to Railway."""
    name = meta.get("name", "nexa-api")
    print(f"\n  🚂 Deploying '{name}' to Railway...")

    if not shutil.which("railway"):
        print("  ⚠️  Railway CLI not found.")
        print("       Install: npm install -g @railway/cli")
        print("       Then:    railway login")
        if not dry_run: sys.exit(1)

    # Generate Procfile
    proc = "web: python -m nexa_lang run main.nexa"
    if not dry_run:
        Path("Procfile").write_text(proc + "\n", encoding="utf-8")
        print("  ✅ Generated Procfile")

    # Generate requirements.txt
    req_txt = "nexa-lang\n"
    if not dry_run:
        Path("requirements.txt").write_text(req_txt, encoding="utf-8")

    rc = _run("railway up", dry_run=dry_run)
    if rc == 0 and not dry_run:
        print(f"\n  ✅ Deployed to Railway!")
    return rc


def deploy_huggingface(meta: dict, dry_run: bool = False):
    """Deploy a Nexa ML model to Hugging Face Spaces (Gradio app)."""
    name    = meta.get("name", "nexa-model")
    hf_user = os.environ.get("HF_USERNAME", "your-username")
    print(f"\n  🤗 Deploying '{name}' to Hugging Face Spaces...")

    # Generate app.py Gradio wrapper
    app_py = f'''import gradio as gr
import subprocess, sys

def run_nexa(code: str) -> str:
    try:
        import tempfile, os
        with tempfile.NamedTemporaryFile(suffix=".nexa", delete=False, mode="w") as f:
            f.write(code)
            tmp = f.name
        result = subprocess.run(
            [sys.executable, "-m", "nexa_lang", "run", tmp],
            capture_output=True, text=True, timeout=30
        )
        os.unlink(tmp)
        return result.stdout or result.stderr
    except Exception as e:
        return f"Error: {{e}}"

demo = gr.Interface(
    fn=run_nexa,
    inputs=gr.Textbox(label="Nexa Code", lines=10, placeholder="print(\\"Hello, Nexa!\\")"),
    outputs=gr.Textbox(label="Output"),
    title="{name} — Nexa Language Playground",
    description="Run Nexa code in the browser via Hugging Face Spaces.",
)

if __name__ == "__main__":
    demo.launch()
'''
    if not dry_run:
        Path("app.py").write_text(app_py, encoding="utf-8")
        Path("requirements.txt").write_text("nexa-lang\ngradio\n", encoding="utf-8")
        print("  ✅ Generated app.py (Gradio wrapper) and requirements.txt")

    # Create and push to HF
    rc = _run(f"huggingface-cli repo create {hf_user}/{name} --type space --space_sdk gradio", dry_run=dry_run)
    if rc == 0 or dry_run:
        _run(f"git init && git add . && git commit -m 'Deploy {name}'", dry_run=dry_run)
        _run(f"git push https://huggingface.co/spaces/{hf_user}/{name} main", dry_run=dry_run)
        if not dry_run:
            print(f"\n  ✅ Deployed! View at: https://huggingface.co/spaces/{hf_user}/{name}")
    return rc


def deploy_fly(meta: dict, dry_run: bool = False):
    """Deploy a Nexa app to Fly.io using Docker."""
    name = meta.get("name", "nexa-app")
    print(f"\n  🪰 Deploying '{name}' to Fly.io...")

    dockerfile = """FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install nexa-lang
CMD ["python", "-m", "nexa_lang", "run", "main.nexa"]
"""
    if not dry_run:
        Path("Dockerfile").write_text(dockerfile, encoding="utf-8")
        print("  ✅ Generated Dockerfile")

    rc = _run(f"fly launch --name {name} --no-deploy", dry_run=dry_run)
    if rc == 0 or dry_run:
        _run("fly deploy", dry_run=dry_run)
        if not dry_run:
            print(f"\n  ✅ Deployed! View at: https://{name}.fly.dev")
    return rc


# ── Main entry point ──────────────────────────────────────────────────────────

def run_deploy(args: list):
    """Entry point for `nexa deploy` CLI command."""
    dry_run = "--dry-run" in args
    target  = "vercel"  # default
    if "--target" in args:
        ti = args.index("--target")
        target = args[ti + 1] if ti + 1 < len(args) else "vercel"

    meta = _check_nexa_json()

    if dry_run:
        print("  🔍 Dry-run mode — no changes will be made\n")

    targets = {
        "vercel":  deploy_vercel,
        "railway": deploy_railway,
        "hf":      deploy_huggingface,
        "fly":     deploy_fly,
    }

    fn = targets.get(target)
    if fn is None:
        print(f"  ❌ Unknown target: '{target}'")
        print(f"  Available targets: {', '.join(targets)}")
        sys.exit(1)

    fn(meta, dry_run=dry_run)
