#!/usr/bin/env bash
# deploy.sh — ArchScript deployment script
#
# Usage:
#   ./deploy.sh              # Show help
#   ./deploy.sh check        # Verify deployment prerequisites
#   ./deploy.sh tag 0.2.0    # Create a release tag (triggers CI/CD)
#   ./deploy.sh cargo        # Publish to crates.io (manual)
#   ./deploy.sh pypi         # Build and publish to PyPI (manual)
#   ./deploy.sh all 0.2.0    # Tag + publish to both registries

set -euo pipefail

# Load .env file if present
if [ -f .env ]; then
    set -a
    # shellcheck source=/dev/null
    source .env
    set +a
fi

VERSION_FILE="Cargo.toml"
CURRENT_VERSION=$(grep '^version' "$VERSION_FILE" | head -1 | sed 's/.*"\(.*\)"/\1/')

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

info()  { echo -e "${GREEN}[INFO]${NC} $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }

# ── Prerequisites check ──────────────────────────────────────────────────────

cmd_check() {
    info "Checking deployment prerequisites..."

    local ok=true

    # Required tools
    for cmd in cargo git rustc; do
        if command -v "$cmd" &>/dev/null; then
            info "  ✓ $cmd ($(command -v "$cmd"))"
        else
            warn "  ✗ $cmd — not found"
            ok=false
        fi
    done

    # Optional tools
    for cmd in maturin pip uv; do
        if command -v "$cmd" &>/dev/null; then
            info "  ✓ $cmd ($(command -v "$cmd"))"
        else
            warn "  ○ $cmd — not found (optional, needed for PyPI publishing)"
        fi
    done

    # Check .env file
    if [ -f .env ]; then
        info "  ✓ .env file found"
    else
        warn "  ○ .env file not found (copy .env.example to .env)"
    fi

    # Check cargo token (from .env or credentials file)
    if [ -n "${CARGO_REGISTRY_TOKEN:-}" ]; then
        info "  ✓ CARGO_REGISTRY_TOKEN set (from .env)"
    elif [ -f "$HOME/.cargo/credentials.toml" ] || [ -f "$HOME/.cargo/credentials" ]; then
        info "  ✓ cargo credentials found (~/.cargo/credentials)"
    else
        warn "  ○ no cargo token — set CARGO_REGISTRY_TOKEN in .env or run: cargo login"
    fi

    # Check PyPI token
    if [ -n "${PYPI_API_TOKEN:-}" ]; then
        info "  ✓ PYPI_API_TOKEN set (from .env)"
    else
        warn "  ○ PYPI_API_TOKEN not set — add to .env for PyPI publishing"
    fi

    # Check git status
    if git diff-index --quiet HEAD -- 2>/dev/null; then
        info "  ✓ git working tree clean"
    else
        warn "  ✗ git working tree has uncommitted changes"
        ok=false
    fi

    info ""
    info "Current version: $CURRENT_VERSION"

    if $ok; then
        info "All checks passed."
    else
        warn "Some checks failed. Fix issues before deploying."
    fi
}

# ── Version bump ──────────────────────────────────────────────────────────────

bump_version() {
    local new_version="$1"

    if [ "$new_version" = "$CURRENT_VERSION" ]; then
        error "New version ($new_version) is the same as current ($CURRENT_VERSION)"
    fi

    info "Bumping version: $CURRENT_VERSION → $new_version"

    # Update Cargo.toml
    sed -i "0,/^version = \"$CURRENT_VERSION\"/s//version = \"$new_version\"/" Cargo.toml
    info "  Updated Cargo.toml"

    # Update pyproject.toml if it exists
    if [ -f pyproject.toml ]; then
        sed -i "s/^version = \"$CURRENT_VERSION\"/version = \"$new_version\"/" pyproject.toml
        info "  Updated pyproject.toml"
    fi

    # Rebuild to update Cargo.lock
    cargo check --quiet 2>/dev/null || true
    info "  Version bump complete"
}

# ── Run tests ─────────────────────────────────────────────────────────────────

run_tests() {
    info "Running test suite..."
    cargo fmt -- --check || error "Format check failed"
    cargo clippy -- -D warnings || error "Clippy check failed"
    cargo test || error "Tests failed"
    info "All tests passed."
}

# ── Tag release ───────────────────────────────────────────────────────────────

cmd_tag() {
    local new_version="${1:-}"
    if [ -z "$new_version" ]; then
        error "Usage: $0 tag <version>  (e.g., $0 tag 0.2.0)"
    fi

    run_tests
    bump_version "$new_version"

    git add Cargo.toml pyproject.toml
    git commit -m "release: v$new_version"
    git tag -a "v$new_version" -m "Release v$new_version"

    info "Tagged v$new_version"
    info ""
    info "Push to trigger CI/CD release:"
    info "  git push origin main --tags"
}

# ── Publish to crates.io ─────────────────────────────────────────────────────

cmd_cargo() {
    info "Publishing to crates.io..."

    run_tests
    cargo publish --dry-run || error "Dry run failed"

    info ""
    read -rp "Publish archscript v$CURRENT_VERSION to crates.io? [y/N] " confirm
    if [[ "$confirm" =~ ^[Yy]$ ]]; then
        if [ -n "${CARGO_REGISTRY_TOKEN:-}" ]; then
            cargo publish --token "$CARGO_REGISTRY_TOKEN"
        else
            cargo publish
        fi
        info "Published to crates.io: https://crates.io/crates/archscript"
    else
        info "Aborted."
    fi
}

# ── Build and publish to PyPI ─────────────────────────────────────────────────

cmd_pypi() {
    info "Publishing to PyPI..."

    if ! command -v maturin &>/dev/null; then
        info "Installing maturin..."
        pip install maturin || uv pip install maturin || error "Failed to install maturin"
    fi

    run_tests

    info "Building wheel..."
    maturin build --release --out dist/

    info ""
    info "Built wheels:"
    ls -la dist/*.whl 2>/dev/null || error "No wheels found in dist/"
    info ""

    read -rp "Upload archscript v$CURRENT_VERSION to PyPI? [y/N] " confirm
    if [[ "$confirm" =~ ^[Yy]$ ]]; then
        if [ -n "${PYPI_API_TOKEN:-}" ]; then
            MATURIN_PYPI_TOKEN="$PYPI_API_TOKEN" maturin upload dist/*.whl
        else
            maturin upload dist/*.whl
        fi
        info "Published to PyPI: https://pypi.org/project/archscript/"
    else
        info "Aborted."
    fi
}

# ── Full release ──────────────────────────────────────────────────────────────

cmd_all() {
    local new_version="${1:-}"
    if [ -z "$new_version" ]; then
        error "Usage: $0 all <version>  (e.g., $0 all 0.2.0)"
    fi

    cmd_tag "$new_version"

    info ""
    info "Publishing to registries..."

    # Re-read version after bump
    CURRENT_VERSION="$new_version"

    cmd_cargo
    cmd_pypi

    info ""
    info "Release v$new_version complete!"
    info ""
    info "Clients can now install via:"
    info "  cargo install archscript              # from crates.io"
    info "  pip install archscript                # from PyPI"
    info "  uv pip install archscript             # from PyPI (fast)"
    info "  uv tool install archscript            # as a CLI tool"
}

# ── Help ──────────────────────────────────────────────────────────────────────

cmd_help() {
    cat <<'HELP'
ArchScript Deployment Script

Usage: ./deploy.sh <command> [args]

Commands:
  check           Verify deployment prerequisites
  tag <version>   Bump version, commit, and create a git tag
  cargo           Publish current version to crates.io
  pypi            Build and publish current version to PyPI
  all <version>   Full release: tag + cargo + pypi

Automated release (recommended):
  1. ./deploy.sh tag 0.2.0        # Creates v0.2.0 tag
  2. git push origin main --tags  # CI builds & publishes everywhere

Manual release:
  1. ./deploy.sh cargo            # Publish to crates.io
  2. ./deploy.sh pypi             # Build wheel & publish to PyPI

Client installation:
  cargo install archscript            # Rust/crates.io
  pip install archscript              # Python/PyPI
  uv pip install archscript           # Python/PyPI (fast)
  uv tool install archscript          # standalone CLI tool

Environment variables (.env):
  Copy .env.example to .env and configure your tokens:
    cp .env.example .env
  Supported variables:
    CARGO_REGISTRY_TOKEN  — crates.io API token
    PYPI_API_TOKEN        — PyPI API token
    GITHUB_TOKEN          — GitHub token (optional)

Version control:
  Versions follow SemVer (MAJOR.MINOR.PATCH).
  Tags trigger the GitHub Actions release workflow which:
    - Runs the full test suite
    - Builds binaries for Linux x86_64, macOS x86_64, macOS ARM
    - Publishes to crates.io
    - Builds and publishes Python wheels to PyPI
    - Creates a GitHub Release with binary artifacts

HELP
}

# ── Main dispatch ─────────────────────────────────────────────────────────────

case "${1:-help}" in
    check) cmd_check ;;
    tag)   cmd_tag "${2:-}" ;;
    cargo) cmd_cargo ;;
    pypi)  cmd_pypi ;;
    all)   cmd_all "${2:-}" ;;
    help|--help|-h) cmd_help ;;
    *) error "Unknown command: $1 (run $0 help for usage)" ;;
esac
