#!/usr/bin/env bash

# Conventional commit helper
# Usage: gc [type] [message] [-s scope] [-b] [-B body]
#        gc -e [type]           (open in editor with template)
#        gc (interactive mode)

set -o errexit
set -o nounset

TYPES="feat fix docs style refactor test chore perf ci build"

usage() {
    echo "Usage: gc [type] [message] [--scope scope] [-b] [-B body]"
    echo '       gc -e [type]                 # open in $EDITOR'
    echo "       gc (interactive mode)"
    echo ""
    echo "Options:"
    echo '  -e, --edit     Open commit message in $EDITOR'
    echo "  --scope        Scope of the change"
    echo "  -b, --breaking Mark as breaking change (!)"
    echo "  -B, --body     Commit body (longer description)"
    echo ""
    echo "Git passthrough flags:"
    echo "  -s, --signoff  Add Signed-off-by trailer"
    echo "  -a, --all      Stage all modified files"
    echo "  -S, --gpg-sign GPG sign the commit"
    echo "  -v, --verbose  Show diff in editor"
    echo "  --amend        Amend previous commit"
    echo ""
    echo "Types: $TYPES"
    echo ""
    echo "Examples:"
    echo "  gc feat 'add user auth'"
    echo "  gc fix 'resolve crash' -s api     # fix(api): resolve crash"
    echo "  gc feat 'new api' -b              # feat!: new api"
    echo "  gc feat 'new api' -s auth -b      # feat(auth)!: new api"
    echo "  gc feat 'big change' -B 'Details here'"
    echo '  gc -e feat                        # edit feat commit in $EDITOR'
    exit 1
}

editor_mode() {
    local type="$1"
    shift
    local git_args=("$@")
    local template

    template=$(mktemp)
    trap "rm -f $template" EXIT

    cat >"$template" <<'EOF'

# Conventional Commit Format:
# <type>(<scope>)!: <description>
#
# [optional body]
#
# [optional footer(s)]
#
# Types: feat fix docs style refactor test chore perf ci build
# Add ! before : for breaking changes (e.g., feat!: or feat(api)!:)
#
# Examples:
#   feat: add user authentication
#   fix(api): resolve null pointer exception
#   feat(auth)!: change token format
#   docs: update API documentation
EOF

    # Prepend type if provided
    if [ -n "$type" ]; then
        sed -i.bak "1s/^/$type: /" "$template" && rm -f "$template.bak"
    fi

    git commit -e -t "$template" "${git_args[@]}"
}

build_message() {
    local type="$1"
    local scope="$2"
    local breaking="$3"
    local msg="$4"
    local body="$5"

    local commit_msg="$type"

    if [ -n "$scope" ]; then
        commit_msg+="($scope)"
    fi

    if [ "$breaking" = "true" ]; then
        commit_msg+="!"
    fi

    commit_msg+=": $msg"

    if [ -n "$body" ]; then
        commit_msg+=$'\n\n'"$body"
    fi

    echo "$commit_msg"
}

# Interactive mode if no args
if [ $# -eq 0 ]; then
    echo "Types: $TYPES"
    printf "Type: "
    read -r type
    printf "Scope (optional): "
    read -r scope
    printf "Breaking change? [y/N]: "
    read -r breaking_input
    printf "Message: "
    read -r msg
    printf "Body (optional, enter for none): "
    read -r body

    breaking="false"
    if [[ $breaking_input =~ ^[Yy] ]]; then
        breaking="true"
    fi

    commit_msg=$(build_message "$type" "$scope" "$breaking" "$msg" "$body")
    git commit -m "$commit_msg"
    exit 0
fi

# Parse arguments
type=""
msg=""
scope=""
breaking="false"
body=""
use_editor="false"
git_args=()

while [ $# -gt 0 ]; do
    case "$1" in
    -e | --edit)
        use_editor="true"
        shift
        ;;
    --scope)
        scope="$2"
        shift 2
        ;;
    -b | --breaking)
        breaking="true"
        shift
        ;;
    -B | --body)
        body="$2"
        shift 2
        ;;
    -h | --help)
        usage
        ;;
    # Pass through git commit flags
    -s | --signoff | -a | --all | -v | --verbose | -n | --no-verify | --amend | --no-edit)
        git_args+=("$1")
        shift
        ;;
    -S | --gpg-sign)
        git_args+=("$1")
        shift
        ;;
    *)
        if [ -z "$type" ]; then
            type="$1"
        else
            msg="$1"
        fi
        shift
        ;;
    esac
done

# Editor mode
if [ "$use_editor" = "true" ]; then
    editor_mode "$type" "${git_args[@]}"
    exit 0
fi

# Validate type
if ! echo "$TYPES" | grep -qw "$type"; then
    echo "Invalid type: $type"
    echo "Valid types: $TYPES"
    exit 1
fi

if [ -z "$msg" ]; then
    echo "Message required"
    usage
fi

commit_msg=$(build_message "$type" "$scope" "$breaking" "$msg" "$body")
git commit -m "$commit_msg" "${git_args[@]}"
