#!/bin/bash

set -e

# Auto mode flag
AUTO_MODE=false

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Paths
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HOMEBREW_REPO="../homebrew-lumen"
FORMULA_PATH="$HOMEBREW_REPO/Formula/lumen.rb"

# Helper functions
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }

confirm() {
    local prompt="$1"
    local response
    if [[ "$AUTO_MODE" == true ]]; then
        echo -e "${YELLOW}$prompt [y/N]${NC} y (auto)"
        return 0
    fi
    echo -en "${YELLOW}$prompt [y/N]${NC} "
    read -r response
    [[ "$response" =~ ^[Yy]$ ]]
}

prompt_input() {
    local prompt="$1"
    local var_name="$2"
    local default="$3"
    local response
    
    if [[ -n "$default" ]]; then
        echo -en "${BLUE}$prompt${NC} [${default}]: "
    else
        echo -en "${BLUE}$prompt${NC}: "
    fi
    read -r response
    
    if [[ -z "$response" && -n "$default" ]]; then
        eval "$var_name='$default'"
    else
        eval "$var_name='$response'"
    fi
}

# Get current version from Cargo.toml
get_current_version() {
    grep '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/'
}

# Validate semantic version
validate_version() {
    local version="$1"
    if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        error "Invalid version format: $version. Expected format: X.Y.Z"
    fi
}

# Check prerequisites
check_prerequisites() {
    info "Checking prerequisites..."
    
    # Check if we're in a git repo
    if ! git rev-parse --is-inside-work-tree &>/dev/null; then
        error "Not in a git repository"
    fi
    
    # Check for uncommitted changes (excluding Cargo.toml and Cargo.lock)
    if [[ -n $(git status --porcelain | grep -v 'Cargo.toml' | grep -v 'Cargo.lock') ]]; then
        warn "You have uncommitted changes (other than Cargo.toml/Cargo.lock):"
        git status --short | grep -v 'Cargo.toml' | grep -v 'Cargo.lock'
        if ! confirm "Continue anyway?"; then
            exit 1
        fi
    fi
    
    # Check if cargo is installed
    if ! command -v cargo &>/dev/null; then
        error "cargo is not installed"
    fi
    
    # Check if gh CLI is installed
    if ! command -v gh &>/dev/null; then
        error "GitHub CLI (gh) is not installed. Install with: brew install gh"
    fi
    
    # Check if gh is authenticated
    if ! gh auth status &>/dev/null; then
        error "GitHub CLI is not authenticated. Run: gh auth login"
    fi
    
    # Check if homebrew repo exists
    if [[ ! -d "$HOMEBREW_REPO" ]]; then
        error "Homebrew repo not found at $HOMEBREW_REPO"
    fi
    
    # Check if Formula file exists
    if [[ ! -f "$FORMULA_PATH" ]]; then
        error "Formula file not found at $FORMULA_PATH"
    fi
    
    success "All prerequisites met"
}

# Step 1: Update version in Cargo.toml and Cargo.lock
update_cargo_version() {
    local new_version="$1"
    info "Updating Cargo.toml version to $new_version..."
    
    sed -i '' "s/^version = \".*\"/version = \"$new_version\"/" Cargo.toml
    
    # Verify the change
    local updated_version
    updated_version=$(get_current_version)
    if [[ "$updated_version" != "$new_version" ]]; then
        error "Failed to update Cargo.toml version"
    fi
    
    # Update Cargo.lock - need to update the package version directly
    info "Updating Cargo.lock..."
    # Find and replace the version for the lumen package in Cargo.lock
    # The format is: name = "lumen" followed by version = "X.Y.Z"
    sed -i '' '/^name = "lumen"$/{n;s/^version = ".*"/version = "'"$new_version"'"/;}' Cargo.lock
    
    # Run cargo check to ensure Cargo.lock is valid and update any dependency changes
    cargo check --quiet 2>/dev/null || cargo check
    
    success "Cargo.toml and Cargo.lock updated"
}

# Step 2: Commit version changes
commit_version_changes() {
    local version="$1"
    info "Committing version changes..."
    
    git add Cargo.toml Cargo.lock
    git commit -m "chore: bump version to $version"
    
    success "Version changes committed"
}

# Step 3: Publish to crates.io
publish_to_crates() {
    info "Publishing to crates.io..."
    
    if [[ "$AUTO_MODE" != true ]]; then
        if confirm "Run 'cargo publish --dry-run' first?"; then
            cargo publish --dry-run
            if ! confirm "Dry run successful. Proceed with actual publish?"; then
                error "Aborted by user"
            fi
        fi
    fi
    
    cargo publish
    
    success "Published to crates.io"
}

# Target architectures for macOS
TARGETS=("x86_64-apple-darwin" "aarch64-apple-darwin")

# Step 4: Build release binaries for all targets
build_release() {
    info "Building release binaries for all architectures..."
    
    for target in "${TARGETS[@]}"; do
        info "Building for $target..."
        
        # Ensure the target is installed
        if ! rustup target list --installed | grep -q "$target"; then
            info "Installing target $target..."
            rustup target add "$target"
        fi
        
        cargo build --release --target "$target"
        
        if [[ ! -f "target/$target/release/lumen" ]]; then
            error "Release binary not found at target/$target/release/lumen"
        fi
        
        success "Built for $target"
    done
    
    success "All release binaries built"
}

# Step 5: Create tarballs for each architecture
create_tarball() {
    info "Creating tarballs for all architectures..."
    
    for target in "${TARGETS[@]}"; do
        info "Creating tarball for $target..."
        
        cd "target/$target/release"
        tar -czf "lumen-$target.tar.gz" lumen
        cd "$SCRIPT_DIR"
        
        if [[ ! -f "target/$target/release/lumen-$target.tar.gz" ]]; then
            error "Failed to create tarball for $target"
        fi
        
        success "Tarball created for $target"
    done
    
    success "All tarballs created"
}

# Step 6: Calculate SHA256 for each architecture
calculate_sha256() {
    local target="$1"
    local sha256
    sha256=$(shasum -a 256 "target/$target/release/lumen-$target.tar.gz" | awk '{print $1}')
    echo "$sha256"
}

# Generate release notes from commits since last tag
generate_release_notes() {
    local version="$1"
    local last_tag
    local notes="## What's Changed\n\n"
    
    # Get the last tag (most recent tag before HEAD)
    last_tag=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
    
    if [[ -z "$last_tag" ]]; then
        # No previous tag, get all commits
        info "No previous tag found, including all commits" >&2
        while IFS= read -r line; do
            local hash=$(echo "$line" | cut -d' ' -f1)
            local message=$(echo "$line" | cut -d' ' -f2-)
            notes+="* $message ([${hash:0:7}](https://github.com/jnsahaj/lumen/commit/$hash))\n"
        done < <(git log --oneline --format="%H %s")
    else
        info "Generating changelog since $last_tag" >&2
        while IFS= read -r line; do
            local hash=$(echo "$line" | cut -d' ' -f1)
            local message=$(echo "$line" | cut -d' ' -f2-)
            notes+="* $message ([${hash:0:7}](https://github.com/jnsahaj/lumen/commit/$hash))\n"
        done < <(git log --oneline --format="%H %s" "$last_tag"..HEAD)
    fi
    
    echo -e "$notes"
}

# Step 7: Create GitHub release and upload
create_github_release() {
    local version="$1"
    local tag="v$version"
    
    info "Creating GitHub release $tag..."
    
    # Check if tag already exists
    if git tag -l | grep -q "^$tag$"; then
        warn "Tag $tag already exists locally"
        if ! confirm "Delete and recreate tag?"; then
            error "Aborted by user"
        fi
        git tag -d "$tag"
    fi
    
    # Create and push tag
    git tag "$tag"
    git push origin "$tag"
    
    # Generate release notes
    local release_notes
    release_notes=$(generate_release_notes "$version")
    
    # Collect all tarballs
    local tarballs=()
    for target in "${TARGETS[@]}"; do
        tarballs+=("target/$target/release/lumen-$target.tar.gz")
    done
    
    # Create release with gh CLI
    gh release create "$tag" \
        --title "v$version" \
        --notes "$release_notes" \
        "${tarballs[@]}"
    
    success "GitHub release created and tarballs uploaded"
}

# Step 8: Update homebrew formula
update_homebrew_formula() {
    local version="$1"
    local sha256_intel="$2"
    local sha256_arm="$3"
    local url_intel="https://github.com/jnsahaj/lumen/releases/download/v$version/lumen-x86_64-apple-darwin.tar.gz"
    local url_arm="https://github.com/jnsahaj/lumen/releases/download/v$version/lumen-aarch64-apple-darwin.tar.gz"
    
    info "Updating homebrew formula..."
    
    cd "$HOMEBREW_REPO"
    
    # Pull latest changes
    git pull origin main --rebase
    
    # Generate new formula content
    cat > Formula/lumen.rb << EOF
class Lumen < Formula
  desc "lumen is a command-line tool that can show pretty diff, generate commit messages with AI, summarise diffs / commits, and more without requiring an API key."
  homepage "https://github.com/jnsahaj/lumen"
  version "$version"

  on_intel do
    url "$url_intel"
    sha256 "$sha256_intel"
  end

  on_arm do
    url "$url_arm"
    sha256 "$sha256_arm"
  end

  def install
    bin.install "lumen"
  end
end
EOF
    
    # Show the diff
    echo ""
    info "Changes to Formula/lumen.rb:"
    git diff Formula/lumen.rb
    echo ""
    
    if ! confirm "Commit and push these changes?"; then
        git checkout Formula/lumen.rb
        cd "$SCRIPT_DIR"
        error "Aborted by user"
    fi
    
    # Commit and push
    git add Formula/lumen.rb
    git commit -m "chore: Bump ver to $version"
    git push origin main
    
    cd "$SCRIPT_DIR"
    
    success "Homebrew formula updated and pushed"
}

# Push main branch changes
push_main_changes() {
    info "Pushing changes to main branch..."
    
    git push origin main
    
    success "Changes pushed to main"
}

# Main release flow
main() {
    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --auto|-a)
                AUTO_MODE=true
                shift
                ;;
            *)
                shift
                ;;
        esac
    done
    
    echo ""
    echo -e "${GREEN}========================================${NC}"
    echo -e "${GREEN}       Lumen Release Script${NC}"
    echo -e "${GREEN}========================================${NC}"
    if [[ "$AUTO_MODE" == true ]]; then
        echo -e "${GREEN}           (Auto Mode)${NC}"
    fi
    echo ""
    
    # Change to script directory
    cd "$SCRIPT_DIR"
    
    # Check prerequisites
    check_prerequisites
    
    # Get current version
    local current_version
    current_version=$(get_current_version)
    info "Current version: $current_version"
    
    # Prompt for new version
    local new_version
    prompt_input "Enter new version" new_version ""
    
    if [[ -z "$new_version" ]]; then
        error "Version cannot be empty"
    fi
    
    validate_version "$new_version"
    
    if [[ "$new_version" == "$current_version" ]]; then
        error "New version is the same as current version"
    fi
    
    echo ""
    echo -e "${YELLOW}Release Plan:${NC}"
    echo "  1. Update Cargo.toml version to $new_version"
    echo "  2. Commit Cargo.toml and Cargo.lock"
    echo "  3. Publish to crates.io"
    echo "  4. Build release binaries (Intel + ARM)"
    echo "  5. Create tarballs for each architecture"
    echo "  6. Create GitHub release v$new_version and upload tarballs"
    echo "  7. Push main branch changes"
    echo "  8. Update homebrew formula (with arch-specific URLs)"
    echo ""
    
    if ! confirm "Proceed with release?"; then
        error "Aborted by user"
    fi
    
    echo ""
    
    # Execute release steps
    update_cargo_version "$new_version"
    echo ""
    
    commit_version_changes "$new_version"
    echo ""
    
    publish_to_crates
    echo ""
    
    build_release
    echo ""
    
    create_tarball
    echo ""
    
    local sha256_intel sha256_arm
    sha256_intel=$(calculate_sha256 "x86_64-apple-darwin")
    sha256_arm=$(calculate_sha256 "aarch64-apple-darwin")
    info "SHA256 (Intel): $sha256_intel"
    info "SHA256 (ARM):   $sha256_arm"
    echo ""
    
    create_github_release "$new_version"
    echo ""
    
    push_main_changes
    echo ""
    
    update_homebrew_formula "$new_version" "$sha256_intel" "$sha256_arm"
    echo ""
    
    echo -e "${GREEN}========================================${NC}"
    echo -e "${GREEN}  Release v$new_version Complete!${NC}"
    echo -e "${GREEN}========================================${NC}"
    echo ""
    echo "Summary:"
    echo "  - Cargo.toml updated to v$new_version"
    echo "  - Published to crates.io"
    echo "  - GitHub release: https://github.com/jnsahaj/lumen/releases/tag/v$new_version"
    echo "  - Homebrew formula updated"
    echo ""
    echo "Users can now install with: brew install jnsahaj/lumen/lumen"
    echo ""
}

# Run main function
main "$@"
