#!/bin/sh
# Masonry CLI Installer
# Usage: curl -sSL https://media.masonry.so/cli/install.sh | sh
#    or: curl -sSL https://media.masonry.so/cli/install.sh | sh -s -- --version v1.0.0

set -e

# Configuration
# Default to ~/.local/bin (user-writable, no sudo required)
# Falls back to /usr/local/bin if ~/.local/bin doesn't exist and user has sudo
DEFAULT_INSTALL_DIR="$HOME/.local/bin"
INSTALL_DIR="${MASONRY_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
BINARY_NAME="masonry"
BASE_URL="${MASONRY_DOWNLOAD_URL:-https://media.masonry.so/cli}"
LATEST_URL="${BASE_URL}/latest"

# Colors (if terminal supports it)
if [ -t 1 ]; then
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[0;33m'
    BLUE='\033[0;34m'
    NC='\033[0m'
else
    RED=''
    GREEN=''
    YELLOW=''
    BLUE=''
    NC=''
fi

info() { printf "${BLUE}info${NC}: %s\n" "$1"; }
success() { printf "${GREEN}success${NC}: %s\n" "$1"; }
warn() { printf "${YELLOW}warn${NC}: %s\n" "$1"; }
error() { printf "${RED}error${NC}: %s\n" "$1" >&2; exit 1; }

# Detect OS
detect_os() {
    case "$(uname -s)" in
        Darwin*)  echo "darwin" ;;
        Linux*)   echo "linux" ;;
        MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
        *)        error "Unsupported operating system: $(uname -s)" ;;
    esac
}

# Detect architecture
detect_arch() {
    case "$(uname -m)" in
        x86_64|amd64)  echo "amd64" ;;
        arm64|aarch64) echo "arm64" ;;
        *)             error "Unsupported architecture: $(uname -m)" ;;
    esac
}

# Get latest version from CDN
get_latest_version() {
    if command -v curl >/dev/null 2>&1; then
        curl -sSL "$LATEST_URL" | tr -d '[:space:]'
    elif command -v wget >/dev/null 2>&1; then
        wget -qO- "$LATEST_URL" | tr -d '[:space:]'
    else
        error "curl or wget required"
    fi
}

# Download file
download() {
    url="$1"
    output="$2"

    if command -v curl >/dev/null 2>&1; then
        curl -fsSL "$url" -o "$output"
    elif command -v wget >/dev/null 2>&1; then
        wget -q "$url" -O "$output"
    else
        error "curl or wget required"
    fi
}

# Compute SHA256 hash
compute_sha256() {
    file="$1"
    if command -v sha256sum >/dev/null 2>&1; then
        sha256sum "$file" | awk '{print $1}'
    elif command -v shasum >/dev/null 2>&1; then
        shasum -a 256 "$file" | awk '{print $1}'
    elif command -v openssl >/dev/null 2>&1; then
        openssl dgst -sha256 "$file" | awk '{print $NF}'
    else
        echo ""
    fi
}

# Verify checksum
verify_checksum() {
    file="$1"
    expected="$2"

    if [ -z "$expected" ]; then
        warn "No checksum available, skipping verification"
        return 0
    fi

    actual=$(compute_sha256 "$file")
    if [ -z "$actual" ]; then
        warn "No SHA256 tool available, skipping verification"
        return 0
    fi

    if [ "$actual" != "$expected" ]; then
        error "Checksum verification failed!
  Expected: ${expected}
  Got:      ${actual}

This could indicate a corrupted download or tampering.
Please try again or download manually from GitHub."
    fi

    success "Checksum verified: ${actual}"
}

# Get expected checksum from checksums file
get_expected_checksum() {
    checksums_file="$1"
    filename="$2"

    if [ ! -f "$checksums_file" ]; then
        echo ""
        return
    fi

    # Format: <hash>  <filename> or <hash> <filename>
    grep -E "(^| )${filename}$" "$checksums_file" | awk '{print $1}' | head -1
}

# Main installation
main() {
    # Parse arguments
    VERSION=""
    SKIP_CHECKSUM=""
    while [ $# -gt 0 ]; do
        case "$1" in
            --version|-v)
                VERSION="$2"
                shift 2
                ;;
            --skip-checksum)
                SKIP_CHECKSUM="1"
                shift
                ;;
            --help|-h)
                echo "Masonry CLI Installer"
                echo ""
                echo "Usage: curl -sSL https://media.masonry.so/cli/install.sh | sh"
                echo "       curl -sSL https://media.masonry.so/cli/install.sh | sh -s -- --version v1.0.0"
                echo ""
                echo "Options:"
                echo "  --version, -v      Install specific version"
                echo "  --skip-checksum    Skip SHA256 verification (not recommended)"
                echo "  --help, -h         Show this help"
                echo ""
                echo "Environment variables:"
                echo "  MASONRY_INSTALL_DIR    Installation directory (default: /usr/local/bin)"
                echo "  MASONRY_DOWNLOAD_URL   Custom download URL base"
                exit 0
                ;;
            *)
                shift
                ;;
        esac
    done

    info "Masonry CLI Installer"
    echo ""

    # Detect platform
    OS=$(detect_os)
    ARCH=$(detect_arch)
    info "Detected platform: ${OS}/${ARCH}"

    # Get version
    if [ -z "$VERSION" ]; then
        info "Fetching latest version..."
        VERSION=$(get_latest_version)
        if [ -z "$VERSION" ]; then
            error "Failed to get latest version. Specify with --version"
        fi
    fi
    info "Version: ${VERSION}"

    # Construct download URLs
    FILENAME="${BINARY_NAME}-${OS}-${ARCH}"
    if [ "$OS" = "windows" ]; then
        FILENAME="${FILENAME}.exe"
    fi
    DOWNLOAD_URL="${BASE_URL}/${VERSION}/${FILENAME}"
    CHECKSUMS_URL="${BASE_URL}/${VERSION}/checksums.txt"

    # Create temp directory
    TMP_DIR=$(mktemp -d)
    trap 'rm -rf "$TMP_DIR"' EXIT

    # Download checksums file first (for verification)
    EXPECTED_CHECKSUM=""
    if [ -z "$SKIP_CHECKSUM" ]; then
        info "Downloading checksums..."
        if download "$CHECKSUMS_URL" "${TMP_DIR}/checksums.txt" 2>/dev/null; then
            EXPECTED_CHECKSUM=$(get_expected_checksum "${TMP_DIR}/checksums.txt" "$FILENAME")
            if [ -z "$EXPECTED_CHECKSUM" ]; then
                warn "Checksum for ${FILENAME} not found in checksums.txt"
            fi
        else
            warn "Could not download checksums.txt, skipping verification"
        fi
    fi

    # Download binary
    info "Downloading ${FILENAME}..."
    download "$DOWNLOAD_URL" "${TMP_DIR}/${BINARY_NAME}"

    # Verify checksum
    if [ -z "$SKIP_CHECKSUM" ]; then
        info "Verifying checksum..."
        verify_checksum "${TMP_DIR}/${BINARY_NAME}" "$EXPECTED_CHECKSUM"
    else
        warn "Checksum verification skipped (--skip-checksum)"
    fi

    # Make executable
    chmod +x "${TMP_DIR}/${BINARY_NAME}"

    # Verify binary works
    info "Verifying binary..."
    if ! "${TMP_DIR}/${BINARY_NAME}" version >/dev/null 2>&1; then
        error "Downloaded binary failed execution test"
    fi

    # Create install directory if needed
    if [ ! -d "$INSTALL_DIR" ]; then
        info "Creating ${INSTALL_DIR}..."
        mkdir -p "$INSTALL_DIR" 2>/dev/null || {
            error "Failed to create ${INSTALL_DIR}. Try: MASONRY_INSTALL_DIR=/usr/local/bin $0"
        }
    fi

    # Install (overwrite existing)
    EXISTING=""
    if [ -f "${INSTALL_DIR}/${BINARY_NAME}" ]; then
        EXISTING="(replacing existing)"
    fi
    info "Installing to ${INSTALL_DIR}... ${EXISTING}"
    if [ -w "$INSTALL_DIR" ]; then
        rm -f "${INSTALL_DIR}/${BINARY_NAME}"
        mv "${TMP_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}"
    else
        error "Cannot write to ${INSTALL_DIR}. Try with sudo or set MASONRY_INSTALL_DIR to a writable path."
    fi

    echo ""
    success "Masonry CLI installed successfully!"
    echo ""
    echo "  Version:  $VERSION"
    echo "  Location: ${INSTALL_DIR}/${BINARY_NAME}"

    # Check if install dir is in PATH, add if not
    case ":$PATH:" in
        *":${INSTALL_DIR}:"*) ;;
        *)
            # Detect shell and rc file
            SHELL_NAME=$(basename "$SHELL")
            case "$SHELL_NAME" in
                zsh)  RC_FILE="$HOME/.zshrc" ;;
                bash)
                    # Prefer .bashrc, fall back to .bash_profile on macOS
                    if [ -f "$HOME/.bashrc" ]; then
                        RC_FILE="$HOME/.bashrc"
                    else
                        RC_FILE="$HOME/.bash_profile"
                    fi
                    ;;
                fish) RC_FILE="$HOME/.config/fish/config.fish" ;;
                *)    RC_FILE="$HOME/.profile" ;;
            esac

            # Add to PATH in rc file
            PATH_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\""
            if [ "$SHELL_NAME" = "fish" ]; then
                PATH_LINE="set -gx PATH ${INSTALL_DIR} \$PATH"
            fi

            if ! grep -q "${INSTALL_DIR}" "$RC_FILE" 2>/dev/null; then
                echo "" >> "$RC_FILE"
                echo "# Added by Masonry CLI installer" >> "$RC_FILE"
                echo "$PATH_LINE" >> "$RC_FILE"
                info "Added ${INSTALL_DIR} to PATH in ${RC_FILE}"
                echo ""
                warn "Run 'source ${RC_FILE}' or restart your terminal to use masonry"
            fi
            ;;
    esac

    # Install Claude Code skill if ~/.claude exists
    install_claude_skill

    # Install OpenClaw skill if ~/.openclaw exists
    install_openclaw_skill

    echo ""
    echo "Get started:"
    echo "  1. Start a free trial at https://masonry.so/pricing"
    echo "  2. ${BINARY_NAME} login              # Authenticate"
    echo "  3. ${BINARY_NAME} image \"prompt\"     # Generate an image"
    echo ""
    echo "  ${BINARY_NAME} --help             # See all commands"
    echo ""
}

# Install Claude Code skills using the new Agent Skills standard
install_claude_skill() {
    CLAUDE_SKILLS_DIR="$HOME/.claude/skills"

    # Create skills directory (creates ~/.claude if needed)
    mkdir -p "$CLAUDE_SKILLS_DIR/masonry" 2>/dev/null || return 0

    SKILL_FILE="$CLAUDE_SKILLS_DIR/masonry/SKILL.md"

    # Write the main skill file (Agent Skills standard format)
    cat > "$SKILL_FILE" << 'SKILL_EOF'
---
name: masonry
description: AI-powered image and video generation using the Masonry CLI. Generate images, videos, check job status, and manage media assets.
metadata:
  author: masonry-ai
  version: "1.0"
compatibility: Requires masonry CLI installed (npm install -g @masonryai/cli)
allowed-tools: Bash(masonry:*)
---

# Masonry CLI

The `masonry` CLI provides AI-powered image and video generation capabilities.

## When to use this skill

Use this skill when the user wants to:
- Generate images from text prompts
- Generate videos from text prompts
- Check status of generation jobs
- Download generated media
- List available AI models
- View generation history

## Prerequisites

A Masonry subscription is required. Start a free trial at: https://masonry.so/pricing

## Installation

Run directly without installing:
```bash
npx @masonryai/cli image "your prompt"
```

Or install globally:
```bash
npm install -g @masonryai/cli
```

## Quick Commands

```bash
# Generate image
masonry image "your prompt here" --aspect 16:9

# Generate video
masonry video "your prompt here" --duration 4

# Check job status
masonry job status <job-id>

# Download result
masonry job download <job-id> -o ./output.png

# List available models
masonry models list --type image
masonry models list --type video
```

## Detailed Workflows

### Image Generation

```bash
# Basic generation
masonry image "a sunset over mountains, photorealistic"

# With options
masonry image "cyberpunk cityscape" --aspect 16:9 --model imagen-3.0-generate-002

# Available flags
#   --aspect, -a     Aspect ratio (16:9, 9:16, 1:1)
#   --dimension, -d  Exact size (1920x1080)
#   --model, -m      Model key
#   --output, -o     Output path
#   --negative-prompt What to avoid
#   --seed           Reproducibility seed
```

### Video Generation

```bash
# Basic generation
masonry video "ocean waves crashing on rocks"

# With options
masonry video "drone shot of forest" --duration 6 --aspect 16:9

# Available flags
#   --duration       Length in seconds (4, 6, 8)
#   --aspect, -a     Aspect ratio (16:9, 9:16)
#   --model, -m      Model key
#   --image, -i      First frame image
#   --no-audio       Disable audio generation
```

### Job Management

```bash
# List recent jobs
masonry job list

# Check specific job
masonry job status <job-id>

# Wait for completion and download
masonry job wait <job-id> --download -o ./result.png

# View local history
masonry history list
masonry history pending --sync
```

### Model Discovery

```bash
# List all models
masonry models list

# Filter by type
masonry models list --type video

# Get model parameters
masonry models params veo-3.1-fast-generate-preview
```

## Response Format

All commands return JSON:

```json
{
  "success": true,
  "job_id": "abc-123",
  "status": "pending",
  "check_after_seconds": 10,
  "check_command": "masonry job status abc-123"
}
```

## Authentication

If commands fail with auth errors:

1. Ask the user to open https://masonry.so/auth/cli/remote and copy the token
2. Run: `masonry login --token <TOKEN>`

The `masonry login --remote` command prints the auth URL for reference.

Credentials are stored locally in `~/.masonry/config.json`.
For CI/CD, set `MASONRY_TOKEN` and `MASONRY_WORKSPACE` environment variables instead.

## Feedback

Report issues or suggest improvements at: https://github.com/masonry-so/skills/issues

When filing an issue, include:
- **What was your intent?** What were you trying to accomplish?
- **What worked?** Which parts behaved as expected?
- **What needs improvement?** What went wrong or could be better?
SKILL_EOF

    if [ -f "$SKILL_FILE" ]; then
        info "Installed Claude Code skill: ${SKILL_FILE}"
    fi
}

# Install OpenClaw skill if ~/.openclaw exists
install_openclaw_skill() {
    OPENCLAW_SKILLS_DIR="$HOME/.openclaw/skills"

    # Create skills directory (creates ~/.openclaw if needed)
    mkdir -p "$OPENCLAW_SKILLS_DIR/masonry" 2>/dev/null || return 0

    SKILL_FILE="$OPENCLAW_SKILLS_DIR/masonry/SKILL.md"

    cat > "$SKILL_FILE" << 'SKILL_EOF'
---
name: masonry
description: AI-powered image and video generation. Generate images, videos, manage jobs, and explore models via the masonry CLI.
metadata: {"openclaw":{"emoji":"🧱","requires":{"bins":["masonry"],"env":["MASONRY_TOKEN"]},"install":[{"type":"npm","package":"@masonryai/cli"}],"primaryEnv":"MASONRY_TOKEN","homepage":"https://masonry.so"}}
---

# Masonry CLI

Generate AI-powered images and videos from text prompts.

## When to use

- User wants to generate images or videos
- User asks about available AI models
- User wants to check generation job status or download results
- User asks to create visual content, media, or artwork

## Prerequisites

A Masonry subscription is required. Start a free trial at: https://masonry.so/pricing

If the `masonry` command is not found, install it:
```bash
npm install -g @masonryai/cli
```

## Authentication

If any command returns an auth error:

1. Run: `masonry login --remote`
2. The command prints an auth URL. Send it to the user.
3. User opens the URL in a browser, authenticates, and copies the token.
4. Run: `masonry login --token <TOKEN>`

For environments with `MASONRY_TOKEN` and `MASONRY_WORKSPACE` set, no login is needed.

## Workflow

### 1. Generate content

**Image:**
```bash
masonry image "a sunset over mountains, photorealistic" --aspect 16:9
```

**Video:**
```bash
masonry video "ocean waves crashing on rocks" --duration 4 --aspect 16:9
```

### 2. Handle the response

Commands return JSON immediately:
```json
{
  "success": true,
  "job_id": "abc-123",
  "status": "pending",
  "check_after_seconds": 10,
  "check_command": "masonry job status abc-123"
}
```

### 3. Wait and download

```bash
masonry job wait <job-id>
masonry job download <job-id> -o /tmp/output.png
```

The download command prints a `MEDIA: /path/to/file` line to stderr.
After download completes, output that line so the file is sent to the user:

```
MEDIA: /tmp/output.png
```

## Image flags

| Flag | Short | Description |
|------|-------|-------------|
| `--aspect` | `-a` | Aspect ratio: 16:9, 9:16, 1:1 |
| `--dimension` | `-d` | Exact size: 1920x1080 |
| `--model` | `-m` | Model key |
| `--output` | `-o` | Output file path |
| `--negative-prompt` | | What to avoid |
| `--seed` | | Reproducibility seed |

## Video flags

| Flag | Short | Description |
|------|-------|-------------|
| `--duration` | | Length in seconds: 4, 6, 8 |
| `--aspect` | `-a` | Aspect ratio: 16:9, 9:16 |
| `--model` | `-m` | Model key |
| `--image` | `-i` | First frame image (local file) |
| `--last-image` | | Last frame image (requires --image) |
| `--no-audio` | | Disable audio generation |
| `--seed` | | Reproducibility seed |

## Model discovery

```bash
masonry models list              # All models
masonry models list --type image # Image models only
masonry models list --type video # Video models only
masonry models info <model-key>  # Parameters and usage example
```

## Job management

```bash
masonry job list                          # Recent jobs
masonry job status <job-id>               # Check status
masonry job download <job-id> -o ./file   # Download result
masonry job wait <job-id>                 # Wait for completion
masonry history list                      # Local history
masonry history pending --sync            # Sync pending jobs
```

## Error codes

| Code | Meaning | Action |
|------|---------|--------|
| `AUTH_ERROR` | Not authenticated | Run auth flow above |
| `VALIDATION_ERROR` | Invalid parameter | Check flag values |
| `MODEL_NOT_FOUND` | Unknown model key | Run `masonry models list` |

## Guardrails

- Never fabricate job IDs or model keys. Always use values from command output.
- Never run `masonry login` without `--remote` or `--token` (browser login won't work headless).
- If a job is pending, wait `check_after_seconds` before checking again.
- All output is JSON. Parse it, don't guess.

## Feedback

Report issues or suggest improvements at: https://github.com/masonry-so/skills/issues

When filing an issue, include:
- **What was your intent?** What were you trying to accomplish?
- **What worked?** Which parts behaved as expected?
- **What needs improvement?** What went wrong or could be better?
SKILL_EOF

    if [ -f "$SKILL_FILE" ]; then
        info "Installed OpenClaw skill: ${SKILL_FILE}"
    fi
}

main "$@"
