#!/usr/bin/env bash
set -euo pipefail
#
# 15-release-manager.sh — Release Pipeline Manager
#
# Description:
#   Full release management: version detection, bumping, changelog generation,
#   quality gates, tagging, and platform release creation. Supports multiple
#   languages and version file formats.
#
# Usage:
#   ./15-release-manager.sh                    # Interactive menu
#   ./15-release-manager.sh --bump patch       # Bump patch version
#   ./15-release-manager.sh --bump minor       # Bump minor version
#   ./15-release-manager.sh --bump major       # Bump major version
#   ./15-release-manager.sh --current          # Show current version
#
# Dependencies:
#   securegit (optional, falls back to git)
#   gh (optional, for GitHub releases)
#   glab (optional, for GitLab releases)
#

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/lib/securegit-common.sh"

# ─── Constants ───────────────────────────────────────────────────────────────
readonly PROG_NAME="release-manager"
readonly VERSION="1.0.0"

# ─── Version file detection ─────────────────────────────────────────────────

_detect_version_files() {
    local root="$1"

    if [[ -n "${SG_VERSION_FILES:-}" ]]; then
        echo "$SG_VERSION_FILES"
        return
    fi

    local found=()

    # Rust
    [[ -f "$root/Cargo.toml" ]] && found+=("Cargo.toml")

    # JavaScript / TypeScript
    [[ -f "$root/package.json" ]] && found+=("package.json")

    # Python
    [[ -f "$root/pyproject.toml" ]] && found+=("pyproject.toml")
    [[ -f "$root/setup.py" ]] && found+=("setup.py")
    [[ -f "$root/setup.cfg" ]] && found+=("setup.cfg")

    # Java / Maven
    [[ -f "$root/pom.xml" ]] && found+=("pom.xml")

    # Java / Gradle
    [[ -f "$root/build.gradle" ]] && found+=("build.gradle")
    [[ -f "$root/build.gradle.kts" ]] && found+=("build.gradle.kts")

    # Generic
    [[ -f "$root/version.txt" ]] && found+=("version.txt")
    [[ -f "$root/VERSION" ]] && found+=("VERSION")

    echo "${found[*]}"
}

_extract_version() {
    local root="$1" file="$2"
    local filepath="$root/$file"

    case "$file" in
        Cargo.toml)
            # Match the first version = "x.y.z" (package version, not dependency)
            grep -m1 '^version\s*=' "$filepath" | grep -oP '\d+\.\d+\.\d+' | head -1
            ;;
        package.json)
            grep -oP '"version"\s*:\s*"\K[^"]+' "$filepath" | head -1
            ;;
        pyproject.toml)
            grep -m1 '^version\s*=' "$filepath" | grep -oP '\d+\.\d+\.\d+' | head -1
            ;;
        setup.py)
            grep -oP "version\s*=\s*['\"]?\K[0-9]+\.[0-9]+\.[0-9]+" "$filepath" | head -1
            ;;
        setup.cfg)
            grep -m1 '^version\s*=' "$filepath" | grep -oP '\d+\.\d+\.\d+' | head -1
            ;;
        pom.xml)
            # Get the project version (first <version> after <project>)
            grep -m1 '<version>' "$filepath" | grep -oP '\d+\.\d+\.\d+' | head -1
            ;;
        build.gradle|build.gradle.kts)
            grep -m1 "version\s*=" "$filepath" | grep -oP '\d+\.\d+\.\d+' | head -1
            ;;
        version.txt|VERSION)
            grep -oP '\d+\.\d+\.\d+' "$filepath" | head -1
            ;;
        *)
            echo ""
            ;;
    esac
}

_update_version_in_file() {
    local root="$1" file="$2" old_version="$3" new_version="$4"
    local filepath="$root/$file"

    case "$file" in
        Cargo.toml)
            sed -i "0,/^version\s*=\s*\"$old_version\"/s//version = \"$new_version\"/" "$filepath"
            ;;
        package.json)
            sed -i "s/\"version\"\s*:\s*\"$old_version\"/\"version\": \"$new_version\"/" "$filepath"
            ;;
        pyproject.toml)
            sed -i "0,/^version\s*=\s*\"$old_version\"/s//version = \"$new_version\"/" "$filepath"
            ;;
        setup.py)
            sed -i "s/version\s*=\s*[\"']${old_version}[\"']/version=\"${new_version}\"/" "$filepath"
            ;;
        setup.cfg)
            sed -i "s/^version\s*=\s*$old_version/version = $new_version/" "$filepath"
            ;;
        pom.xml)
            # Update the first <version> occurrence
            sed -i "0,/<version>$old_version<\/version>/s//<version>$new_version<\/version>/" "$filepath"
            ;;
        build.gradle|build.gradle.kts)
            sed -i "0,/version\s*=\s*[\"']${old_version}[\"']/s//version = \"${new_version}\"/" "$filepath"
            ;;
        version.txt|VERSION)
            echo "$new_version" > "$filepath"
            ;;
    esac
}

# ─── Version arithmetic ─────────────────────────────────────────────────────

_bump_version() {
    local current="$1" bump_type="$2"

    local major minor patch
    IFS='.' read -r major minor patch <<< "$current"
    major="${major:-0}"
    minor="${minor:-0}"
    patch="${patch:-0}"

    case "$bump_type" in
        major)
            major=$((major + 1))
            minor=0
            patch=0
            ;;
        minor)
            minor=$((minor + 1))
            patch=0
            ;;
        patch)
            patch=$((patch + 1))
            ;;
        *)
            sg_die "Invalid bump type: $bump_type (expected: major, minor, patch)"
            ;;
    esac

    echo "$major.$minor.$patch"
}

# ─── Changelog generation ───────────────────────────────────────────────────

_generate_changelog() {
    local from_ref="$1" to_ref="$2" version="$3"
    local root
    root="$(git rev-parse --show-toplevel)"

    local changelog_file="$root/CHANGELOG.md"
    local date_str
    date_str="$(date -u +%Y-%m-%d)"

    # Collect commits grouped by type
    local commits
    commits="$(git log "$from_ref..$to_ref" --pretty=format:'%s|||%h|||%an' 2>/dev/null || true)"

    if [[ -z "$commits" ]]; then
        sg_warn "No commits found between $from_ref and $to_ref"
        return 1
    fi

    local features="" fixes="" docs="" refactors="" tests="" chores="" breaking="" other=""

    while IFS= read -r line; do
        [[ -z "$line" ]] && continue
        local msg hash author
        msg="$(echo "$line" | cut -d'|||' -f1)"
        hash="$(echo "$line" | cut -d'|||' -f2)"
        author="$(echo "$line" | cut -d'|||' -f3)"

        # Parse conventional commit type
        local entry="- $msg ($hash)"

        case "$msg" in
            feat*)    features+="$entry"$'\n' ;;
            fix*)     fixes+="$entry"$'\n' ;;
            docs*)    docs+="$entry"$'\n' ;;
            refactor*) refactors+="$entry"$'\n' ;;
            test*)    tests+="$entry"$'\n' ;;
            perf*)    features+="$entry"$'\n' ;;
            chore*|build*|ci*) chores+="$entry"$'\n' ;;
            *)        other+="$entry"$'\n' ;;
        esac

        # Check for breaking changes
        if echo "$msg" | grep -qP '!:|BREAKING CHANGE'; then
            breaking+="$entry"$'\n'
        fi
    done <<< "$commits"

    # Build changelog entry
    local entry_text=""
    entry_text+="## [$version] - $date_str"$'\n\n'

    if [[ -n "$breaking" ]]; then
        entry_text+="### BREAKING CHANGES"$'\n\n'
        entry_text+="$breaking"$'\n'
    fi
    if [[ -n "$features" ]]; then
        entry_text+="### Features"$'\n\n'
        entry_text+="$features"$'\n'
    fi
    if [[ -n "$fixes" ]]; then
        entry_text+="### Bug Fixes"$'\n\n'
        entry_text+="$fixes"$'\n'
    fi
    if [[ -n "$docs" ]]; then
        entry_text+="### Documentation"$'\n\n'
        entry_text+="$docs"$'\n'
    fi
    if [[ -n "$refactors" ]]; then
        entry_text+="### Refactoring"$'\n\n'
        entry_text+="$refactors"$'\n'
    fi
    if [[ -n "$tests" ]]; then
        entry_text+="### Tests"$'\n\n'
        entry_text+="$tests"$'\n'
    fi
    if [[ -n "$chores" ]]; then
        entry_text+="### Chores"$'\n\n'
        entry_text+="$chores"$'\n'
    fi
    if [[ -n "$other" ]]; then
        entry_text+="### Other"$'\n\n'
        entry_text+="$other"$'\n'
    fi

    # Write changelog
    if [[ -f "$changelog_file" ]]; then
        # Insert after the first heading line
        local existing
        existing="$(cat "$changelog_file")"
        local header_line="# Changelog"

        if echo "$existing" | head -1 | grep -qi "changelog"; then
            # Insert new entry after the first line
            local first_line
            first_line="$(head -1 "$changelog_file")"
            local rest
            rest="$(tail -n +2 "$changelog_file")"
            printf '%s\n\n%s\n%s\n' "$first_line" "$entry_text" "$rest" > "$changelog_file"
        else
            # Prepend
            printf '%s\n\n%s\n%s\n' "$header_line" "$entry_text" "$existing" > "$changelog_file"
        fi
    else
        printf '# Changelog\n\n%s\n' "$entry_text" > "$changelog_file"
    fi

    sg_success "Changelog updated: $changelog_file"
    echo "$entry_text"
}

# ─── Quality gates ──────────────────────────────────────────────────────────

_run_quality_gates() {
    sg_header "Running Quality Gates"

    local pass=true

    # Format check
    sg_info "Checking formatting..."
    local fmt_cmd
    fmt_cmd="$(sg_detect_fmt_cmd)"
    if eval "$fmt_cmd" 2>&1; then
        sg_success "Format check passed."
    else
        sg_warn "Format check found issues."
        pass=false
    fi

    # Lint
    sg_info "Running linter..."
    local lint_cmd
    lint_cmd="$(sg_detect_lint_cmd)"
    if eval "$lint_cmd" 2>&1; then
        sg_success "Lint passed."
    else
        sg_error "Lint failed."
        pass=false
    fi

    # Tests
    sg_info "Running tests..."
    local test_cmd
    test_cmd="$(sg_detect_test_cmd)"
    if eval "$test_cmd" 2>&1; then
        sg_success "Tests passed."
    else
        sg_error "Tests failed."
        pass=false
    fi

    # Build
    sg_info "Running build..."
    local build_cmd
    build_cmd="$(sg_detect_build_cmd)"
    if eval "$build_cmd" 2>&1; then
        sg_success "Build passed."
    else
        sg_error "Build failed."
        pass=false
    fi

    # Security scan
    sg_info "Running security scan..."
    if _sg_cmd scan --path "$(git rev-parse --show-toplevel)" 2>/dev/null; then
        sg_success "Security scan passed."
    else
        sg_warn "Security scan found issues."
        pass=false
    fi

    echo
    if [[ "$pass" == "true" ]]; then
        sg_success "All quality gates passed."
        return 0
    else
        sg_error "Some quality gates failed."
        return 1
    fi
}

# ─── Show current version ───────────────────────────────────────────────────

_show_current_version() {
    local root
    root="$(git rev-parse --show-toplevel)"
    local version_files
    version_files="$(_detect_version_files "$root")"

    if [[ -z "$version_files" ]]; then
        sg_warn "No version files detected."
        # Fall back to git tags
        local latest_tag
        latest_tag="$(git describe --tags --abbrev=0 2>/dev/null || echo "none")"
        sg_info "Latest git tag: $latest_tag"
        return
    fi

    sg_header "Current Version"

    local primary_version=""
    for file in $version_files; do
        local ver
        ver="$(_extract_version "$root" "$file")"
        if [[ -n "$ver" ]]; then
            printf "  ${_C_BOLD}%-25s${_C_RESET} %s\n" "$file" "$ver"
            [[ -z "$primary_version" ]] && primary_version="$ver"
        else
            printf "  ${_C_DIM}%-25s (version not found)${_C_RESET}\n" "$file"
        fi
    done

    echo
    local latest_tag
    latest_tag="$(git describe --tags --abbrev=0 2>/dev/null || echo "none")"
    printf "  ${_C_BOLD}%-25s${_C_RESET} %s\n" "Latest git tag:" "$latest_tag"

    local commits_since
    if [[ "$latest_tag" != "none" ]]; then
        commits_since=$(git rev-list --count "$latest_tag..HEAD" 2>/dev/null || echo "?")
        printf "  ${_C_BOLD}%-25s${_C_RESET} %s\n" "Commits since tag:" "$commits_since"
    fi
}

# ─── Bump version ───────────────────────────────────────────────────────────

_do_bump() {
    local bump_type="$1"
    local root
    root="$(git rev-parse --show-toplevel)"

    local version_files
    version_files="$(_detect_version_files "$root")"

    if [[ -z "$version_files" ]]; then
        sg_die "No version files detected. Create a version.txt or set SG_VERSION_FILES."
    fi

    # Determine current version from primary file
    local primary_file current_version
    primary_file="$(echo "$version_files" | awk '{print $1}')"
    current_version="$(_extract_version "$root" "$primary_file")"

    if [[ -z "$current_version" ]]; then
        sg_warn "Could not extract version from $primary_file."
        current_version=$(sg_prompt "Enter current version manually" "0.0.0")
    fi

    local new_version
    if [[ "$bump_type" == "custom" ]]; then
        new_version=$(sg_prompt "Enter new version" "")
        if [[ -z "$new_version" ]]; then
            sg_die "No version provided."
        fi
    else
        new_version="$(_bump_version "$current_version" "$bump_type")"
    fi

    sg_header "Version Bump"
    printf "  ${_C_BOLD}Current:${_C_RESET}  %s\n" "$current_version"
    printf "  ${_C_BOLD}New:${_C_RESET}      %s\n" "$new_version"
    printf "  ${_C_BOLD}Type:${_C_RESET}     %s\n" "$bump_type"
    printf "  ${_C_BOLD}Files:${_C_RESET}    %s\n" "$version_files"
    echo

    if ! sg_confirm "Proceed with version bump?" "y"; then
        sg_info "Version bump cancelled."
        return 1
    fi

    # Update all version files
    local updated_count=0
    for file in $version_files; do
        local file_version
        file_version="$(_extract_version "$root" "$file")"
        if [[ -n "$file_version" ]]; then
            sg_info "Updating $file: $file_version -> $new_version"
            _update_version_in_file "$root" "$file" "$file_version" "$new_version"
            sg_success "Updated $file"
            updated_count=$((updated_count + 1))
        else
            sg_warn "Skipping $file (could not extract version)."
        fi
    done

    # Handle Cargo.lock if Cargo.toml was updated
    if echo "$version_files" | grep -q "Cargo.toml" && command -v cargo &>/dev/null; then
        sg_info "Updating Cargo.lock..."
        (cd "$root" && cargo update --workspace 2>/dev/null || cargo generate-lockfile 2>/dev/null || true)
    fi

    sg_success "Updated $updated_count version file(s) to $new_version."
    sg_undo_available

    echo "$new_version"
}

# ─── Release branch ─────────────────────────────────────────────────────────

_create_release_branch() {
    local version="$1"
    local branch_name="release/v$version"

    if sg_branch_exists "$branch_name"; then
        sg_warn "Release branch '$branch_name' already exists."
        if sg_confirm "Switch to existing branch?" "y"; then
            _sg_cmd checkout "$branch_name"
            return 0
        fi
        return 1
    fi

    sg_info "Creating release branch: $branch_name"
    _sg_cmd checkout -b "$branch_name"
    sg_success "Release branch created: $branch_name"
    sg_undo_available

    echo "$branch_name"
}

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

_create_tag() {
    local version="$1" changelog_entry="$2"
    local tag_name="v$version"

    if git tag -l "$tag_name" | grep -q "$tag_name"; then
        sg_error "Tag '$tag_name' already exists."
        if ! sg_confirm "Delete and recreate?" "n"; then
            return 1
        fi
        _sg_cmd tag -d "$tag_name"
    fi

    sg_info "Creating annotated tag: $tag_name"
    local tag_msg="Release $tag_name"
    if [[ -n "$changelog_entry" ]]; then
        tag_msg="$tag_msg"$'\n\n'"$changelog_entry"
    fi

    _sg_cmd tag -a "$tag_name" -m "$tag_msg"
    sg_success "Tag '$tag_name' created."
    sg_undo_available

    echo "$tag_name"
}

_push_release() {
    local tag_name="$1"
    local remote="${SG_PRIMARY_REMOTE:-origin}"
    local current_branch
    current_branch="$(sg_current_branch)"

    sg_info "Pushing branch '$current_branch' and tag '$tag_name'..."

    _sg_cmd push "$remote" "$current_branch" 2>/dev/null || true
    _sg_cmd push "$remote" "$tag_name"

    sg_success "Pushed branch and tag to $remote."
    sg_undo_available
}

_create_platform_release() {
    local tag_name="$1" version="$2" changelog_entry="$3"
    local platform

    if command -v gh &>/dev/null && gh auth status &>/dev/null 2>&1; then
        platform="github"
    elif command -v glab &>/dev/null && glab auth status &>/dev/null 2>&1; then
        platform="gitlab"
    else
        platform="none"
    fi

    case "$platform" in
        github)
            sg_info "Creating GitHub release for $tag_name..."
            local release_notes="$changelog_entry"
            if [[ -z "$release_notes" ]]; then
                release_notes="Release $version"
            fi
            if gh release create "$tag_name" --title "Release $version" --notes "$release_notes" 2>/dev/null; then
                sg_success "GitHub release created."
                sg_info "Release URL:"
                gh release view "$tag_name" --json url -q '.url' 2>/dev/null || true
            else
                sg_error "Failed to create GitHub release."
            fi
            ;;
        gitlab)
            sg_info "Creating GitLab release for $tag_name..."
            if glab release create "$tag_name" --name "Release $version" --notes "${changelog_entry:-Release $version}" 2>/dev/null; then
                sg_success "GitLab release created."
            else
                sg_error "Failed to create GitLab release."
            fi
            ;;
        none)
            sg_info "No platform CLI detected. Create the release manually in your hosting provider."
            sg_info "Tag: $tag_name"
            ;;
    esac
}

# ─── Backup before release ──────────────────────────────────────────────────

_backup_before_release() {
    if ! command -v securegit &>/dev/null; then
        sg_info "securegit not available, skipping backup."
        return 0
    fi

    sg_info "Creating backup before release..."
    if _sg_cmd backup push 2>/dev/null; then
        sg_success "Backup completed."
    else
        sg_warn "Backup not configured or failed. Consider setting up backup destinations."
        sg_info "Run: securegit backup add --name <name> --destination <path>"
    fi
}

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

_full_release() {
    sg_header "Full Release Pipeline"

    local root
    root="$(git rev-parse --show-toplevel)"

    # Step 1: Show current state
    _show_current_version
    echo

    # Step 2: Choose bump type
    local bump_choice
    bump_choice=$(sg_menu "Version Bump Type" "Patch (bug fixes)" "Minor (new features, backward compatible)" "Major (breaking changes)" "Custom version")
    local bump_type
    case "$bump_choice" in
        1) bump_type="patch" ;;
        2) bump_type="minor" ;;
        3) bump_type="major" ;;
        4) bump_type="custom" ;;
    esac

    # Step 3: Bump version
    local new_version
    new_version="$(_do_bump "$bump_type")"
    if [[ -z "$new_version" ]]; then
        sg_die "Version bump failed."
    fi

    # Step 4: Determine previous tag for changelog
    local prev_tag
    prev_tag="$(git describe --tags --abbrev=0 2>/dev/null || echo "")"
    local from_ref="${prev_tag:-$(git rev-list --max-parents=0 HEAD 2>/dev/null | head -1)}"

    # Step 5: Generate changelog
    sg_info "Generating changelog..."
    local changelog_entry=""
    if changelog_entry="$(_generate_changelog "$from_ref" "HEAD" "$new_version")"; then
        sg_success "Changelog generated."
    else
        sg_warn "Changelog generation had issues."
        changelog_entry=""
    fi

    # Step 6: Create release branch (optional)
    local use_release_branch=false
    if sg_confirm "Create a release branch?" "n"; then
        _create_release_branch "$new_version"
        use_release_branch=true
    fi

    # Step 7: Commit version bump and changelog
    sg_info "Committing release changes..."
    _sg_cmd add -A
    _sg_cmd commit -m "chore: Bump version to $new_version"
    sg_success "Release changes committed."
    sg_undo_available

    # Step 8: Run quality gates
    if sg_confirm "Run quality gates before release?" "y"; then
        if ! _run_quality_gates; then
            sg_error "Quality gates failed."
            if ! sg_confirm "Continue with release despite failures?" "n"; then
                sg_die "Release aborted due to quality gate failure."
            fi
        fi
    fi

    # Step 9: Backup
    _backup_before_release

    # Step 10: Create tag
    local tag_name
    tag_name="$(_create_tag "$new_version" "$changelog_entry")"

    # Step 11: Push
    if sg_confirm "Push release to remote?" "y"; then
        _push_release "$tag_name"
    fi

    # Step 12: Create platform release
    if sg_confirm "Create a release on hosting platform?" "y"; then
        _create_platform_release "$tag_name" "$new_version" "$changelog_entry"
    fi

    # Summary
    sg_header "Release Summary"
    sg_divider
    printf "  ${_C_BOLD}Version:${_C_RESET}     %s\n" "$new_version"
    printf "  ${_C_BOLD}Tag:${_C_RESET}         %s\n" "$tag_name"
    printf "  ${_C_BOLD}Branch:${_C_RESET}      %s\n" "$(sg_current_branch)"
    printf "  ${_C_BOLD}Bump type:${_C_RESET}   %s\n" "$bump_type"
    printf "  ${_C_BOLD}Language:${_C_RESET}    %s\n" "$(sg_detect_language)"
    sg_divider
    echo
    sg_success "Release $new_version complete."
}

# ─── Show release history ───────────────────────────────────────────────────

_show_release_history() {
    sg_header "Release History"

    local tags
    tags="$(git tag -l --sort=-version:refname 'v*' 2>/dev/null || git tag -l --sort=-creatordate 2>/dev/null)"

    if [[ -z "$tags" ]]; then
        sg_info "No release tags found."
        return
    fi

    local count=0
    while IFS= read -r tag; do
        [[ -z "$tag" ]] && continue
        count=$((count + 1))
        (( count > 20 )) && break

        local date author
        date="$(git log -1 --format='%ai' "$tag" 2>/dev/null | cut -d' ' -f1)"
        author="$(git log -1 --format='%an' "$tag" 2>/dev/null)"

        printf "  ${_C_BOLD}%-15s${_C_RESET} ${_C_DIM}%s${_C_RESET}  %s\n" "$tag" "$date" "$author"
    done <<< "$tags"

    echo
    printf "  ${_C_DIM}Showing %d of %d tags${_C_RESET}\n" "$count" "$(echo "$tags" | wc -l)"
}

# ─── Verify release integrity ───────────────────────────────────────────────

_verify_release() {
    sg_header "Verify Release Integrity"

    local tag
    tag=$(sg_prompt "Tag to verify (e.g., v1.2.3)" "$(git describe --tags --abbrev=0 2>/dev/null || echo "")")

    if [[ -z "$tag" ]]; then
        sg_die "No tag specified."
    fi

    if ! git tag -l "$tag" | grep -q "$tag"; then
        sg_die "Tag '$tag' does not exist."
    fi

    sg_info "Verifying tag: $tag"

    # Show tag details
    printf "\n${_C_BOLD}Tag details:${_C_RESET}\n"
    git tag -v "$tag" 2>/dev/null || git show "$tag" --quiet 2>/dev/null

    # Check if tag is on expected branch
    local default_branch
    default_branch="$(sg_default_branch)"
    if git branch --contains "$tag" 2>/dev/null | grep -q "$default_branch"; then
        sg_success "Tag is on $default_branch."
    else
        sg_warn "Tag is NOT on $default_branch."
    fi

    # Check version consistency
    local root
    root="$(git rev-parse --show-toplevel)"
    local version_files
    version_files="$(_detect_version_files "$root")"
    local tag_version
    tag_version="${tag#v}"

    sg_info "Checking version consistency:"
    for file in $version_files; do
        local file_version
        file_version="$(_extract_version "$root" "$file")"
        if [[ "$file_version" == "$tag_version" ]]; then
            sg_success "  $file: $file_version (matches tag)"
        else
            sg_warn "  $file: $file_version (expected: $tag_version)"
        fi
    done
}

# ─── Main ────────────────────────────────────────────────────────────────────

main() {
    sg_require_repo

    # Handle direct arguments
    case "${1:-}" in
        --bump)
            local bump_type="${2:-patch}"
            _do_bump "$bump_type"
            exit 0
            ;;
        --current)
            _show_current_version
            exit 0
            ;;
        --help|-h)
            echo "Usage: $0 [--bump major|minor|patch|custom] [--current] [--help]"
            echo
            echo "Options:"
            echo "  --bump TYPE    Bump version (major, minor, patch, custom)"
            echo "  --current      Show current version"
            echo "  --help         Show this help"
            exit 0
            ;;
    esac

    # Interactive menu
    while true; do
        local choice
        choice=$(sg_menu "Release Manager" \
            "Show current version" \
            "Full release pipeline" \
            "Bump version only" \
            "Generate changelog only" \
            "Create tag only" \
            "Run quality gates" \
            "Release history" \
            "Verify release integrity" \
            "Backup repository" \
            "Exit")

        case "$choice" in
            1)  _show_current_version ;;
            2)  _full_release ;;
            3)  # Bump only
                local bump_choice
                bump_choice=$(sg_menu "Version Bump" "Patch" "Minor" "Major" "Custom")
                case "$bump_choice" in
                    1) _do_bump "patch" ;;
                    2) _do_bump "minor" ;;
                    3) _do_bump "major" ;;
                    4) _do_bump "custom" ;;
                esac
                ;;
            4)  # Changelog only
                local prev_tag new_ver
                prev_tag="$(git describe --tags --abbrev=0 2>/dev/null || echo "")"
                local from_ref="${prev_tag:-$(git rev-list --max-parents=0 HEAD 2>/dev/null | head -1)}"
                new_ver=$(sg_prompt "Version for changelog entry" "${prev_tag:-0.1.0}")
                new_ver="${new_ver#v}"
                _generate_changelog "$from_ref" "HEAD" "$new_ver"
                ;;
            5)  # Tag only
                local tag_ver
                tag_ver=$(sg_prompt "Version to tag (without 'v' prefix)")
                _create_tag "$tag_ver" ""
                ;;
            6)  _run_quality_gates || true ;;
            7)  _show_release_history ;;
            8)  _verify_release ;;
            9)  _backup_before_release ;;
            10) sg_success "Done."
                exit 0
                ;;
        esac

        echo
    done
}

main "$@"
