#!/bin/bash

# increment_and_push.sh - Version increment and git automation script for n_os_tr
# Usage:
#   ./increment_and_push.sh "meaningful git comment"
#   ./increment_and_push.sh --set-version vX.Y.Z "meaningful git comment"
#   ./increment_and_push.sh -m "meaningful git comment"   # minor bump
#   ./increment_and_push.sh -M "meaningful git comment"   # major bump

set -euo pipefail

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

print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }

show_usage() {
    cat <<EOF
n_os_tr increment_and_push.sh

USAGE:
  $0 [OPTIONS] "commit message"

OPTIONS:
  -p, --patch           Increment patch version (default)
  -m, --minor           Increment minor version
  -M, --major           Increment major version
  --set-version vX.Y.Z  Set explicit version
  -h, --help            Show this help

EXAMPLES:
  $0 "Phase update with service hardening"
  $0 -m "Ship identity subsystem scaffolding"
  $0 --set-version v1.0.0 "First stable release"
EOF
}

check_git_repo() {
    if ! git rev-parse --git-dir >/dev/null 2>&1; then
        print_error "Not in a git repository"
        exit 1
    fi
}

current_branch() {
    git branch --show-current
}

latest_version_tag() {
    git tag -l 'v*.*.*' | sort -V | tail -n 1
}

compute_next_version() {
    local bump_type="$1"
    local latest_tag
    latest_tag="$(latest_version_tag)"

    if [[ -z "$latest_tag" ]]; then
        latest_tag="v0.0.0"
        print_warning "No existing semantic tags found. Starting from $latest_tag" >&2
    fi

    local version="${latest_tag#v}"
    if [[ ! "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
        print_error "Latest tag '$latest_tag' is not in vX.Y.Z format"
        exit 1
    fi

    local major="${BASH_REMATCH[1]}"
    local minor="${BASH_REMATCH[2]}"
    local patch="${BASH_REMATCH[3]}"

    case "$bump_type" in
        major)
            major=$((major + 1))
            minor=0
            patch=0
            ;;
        minor)
            minor=$((minor + 1))
            patch=0
            ;;
        patch)
            patch=$((patch + 1))
            ;;
        *)
            print_error "Unknown bump type: $bump_type"
            exit 1
            ;;
    esac

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

COMMIT_MESSAGE=""
TARGET_VERSION=""
BUMP_TYPE="patch"

while [[ $# -gt 0 ]]; do
    case "$1" in
        -p|--patch)
            BUMP_TYPE="patch"
            shift
            ;;
        -m|--minor)
            BUMP_TYPE="minor"
            shift
            ;;
        -M|--major)
            BUMP_TYPE="major"
            shift
            ;;
        --set-version)
            if [[ $# -lt 2 ]]; then
                print_error "--set-version requires a value like v1.2.3"
                exit 1
            fi
            TARGET_VERSION="$2"
            shift 2
            ;;
        -h|--help)
            show_usage
            exit 0
            ;;
        *)
            if [[ -z "$COMMIT_MESSAGE" ]]; then
                COMMIT_MESSAGE="$1"
            else
                COMMIT_MESSAGE+=" $1"
            fi
            shift
            ;;
    esac
done

if [[ -z "$COMMIT_MESSAGE" ]]; then
    print_error "Commit message is required"
    show_usage
    exit 1
fi

check_git_repo

if [[ -n "$TARGET_VERSION" ]]; then
    if [[ ! "$TARGET_VERSION" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
        print_error "Invalid --set-version value '$TARGET_VERSION' (expected vX.Y.Z)"
        exit 1
    fi
    NEW_VERSION="$TARGET_VERSION"
else
    NEW_VERSION="$(compute_next_version "$BUMP_TYPE")"
fi

print_info "Target version: $NEW_VERSION"

print_info "Staging changes..."
git add -A

if git diff --staged --quiet; then
    print_warning "No staged changes to commit"
    exit 0
fi

FULL_COMMIT_MESSAGE="$NEW_VERSION - $COMMIT_MESSAGE"
print_info "Committing: $FULL_COMMIT_MESSAGE"
git commit -m "$FULL_COMMIT_MESSAGE"

if git rev-parse "$NEW_VERSION" >/dev/null 2>&1; then
    print_warning "Tag $NEW_VERSION already exists locally. Re-pointing to current commit."
    git tag -d "$NEW_VERSION" >/dev/null 2>&1 || true
fi

print_info "Creating tag: $NEW_VERSION"
git tag "$NEW_VERSION"

BRANCH="$(current_branch)"
if [[ -z "$BRANCH" ]]; then
    print_error "Could not determine current branch"
    exit 1
fi

print_info "Pushing branch '$BRANCH'..."
if ! git push origin "$BRANCH"; then
    print_warning "Initial push failed. Attempting rebase onto origin/$BRANCH and retrying..."
    git pull --rebase origin "$BRANCH"
    git push origin "$BRANCH"
fi

print_info "Pushing tag '$NEW_VERSION'..."
if ! git push origin "$NEW_VERSION"; then
    print_warning "Tag push failed; attempting force update for tag '$NEW_VERSION'"
    git push --force origin "$NEW_VERSION"
fi

print_success "Done: committed and pushed $NEW_VERSION"
