#!/usr/bin/env bash

set -e

# Function to find the repository root by searching for existing project markers
find_repo_root() {
    local dir="$1"
    while [ "$dir" != "/" ]; do
        if [ -d "$dir/.git" ] || [ -d "$dir/.specify" ]; then
            echo "$dir"
            return 0
        fi
        dir="$(dirname "$dir")"
    done
    return 1
}

# Function to check existing branches (local and remote) and return next available number
check_existing_branches() {
    local short_name="$1"
    local specs_dir="$2"
    
    # Fetch all remotes to get latest branch info (suppress errors if no remotes)
    git fetch --all --prune 2>/dev/null || true
    
    # Find all branches matching the pattern using git ls-remote (more reliable)
    local remote_branches=$(git ls-remote --heads origin 2>/dev/null | grep -E "refs/heads/[0-9]+-${short_name}$" | sed 's/.*\/\([0-9]*\)-.* /\1/' | sort -n)
    
    # Also check local branches
    local local_branches=$(git branch 2>/dev/null | grep -E "^[* ]*[0-9]+-${short_name}$" | sed 's/^[* ]*//' | sed 's/-.*//' | sort -n)
    
    # Check specs directory as well
    local spec_dirs=""
    if [ -d "$specs_dir" ]; then
        spec_dirs=$(find "$specs_dir" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n)
    fi
    
    # Combine all sources and get the highest number
    local max_num=0
    for num in $remote_branches $local_branches $spec_dirs; do
        if [ "$num" -gt "$max_num" ]; then
            max_num=$num
        fi
    done
    
    # Return next number
    echo $((max_num + 1))
}

# Function to generate branch name with stop word filtering and length filtering
generate_branch_name() {
    local description="$1"
    
    # Common stop words to filter out
    local stop_words="^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$"
    
    # Split into words and lowercase
    local words=$(echo "$description" | tr '[:upper:]' '[:lower:]' | tr -s '[:punct:][:space:]' '\n')
    
    local meaningful_words=()
    for word in $words; do
        [[ -z "$word" ]] && continue
        
        # Keep if not a stop word AND (length >= 3 OR uppercase acronym in original)
        if ! echo "$word" | grep -qiE "$stop_words"; then
            if [[ ${#word} -ge 3 ]] || echo "$description" | grep -q "\b${word^^}\b"; then
                meaningful_words+=("$word")
            fi
        fi
    done
    
    if [[ ${#meaningful_words[@]} -gt 0 ]]; then
        # Use first 4 meaningful words joined by hyphens
        printf "%s\n" "${meaningful_words[@]}" | head -n 4 | tr '\n' '-' | sed 's/-$//'
    else
        # Fallback: just take first 3 non-empty words
        echo "$description" | tr '[:upper:]' '[:lower:]' | tr -s '[:punct:][:space:]' '\n' | grep -v '^$' | head -n 3 | tr '\n' '-' | sed 's/-$//'
    fi
}

main() {
    local json_mode=false
    local short_name=""
    local branch_number=""
    local args=()
    local i=1
    
    while [ $i -le $# ]; do
        local arg="${!i}"
        case "$arg" in
            --json) 
                json_mode=true 
                ;;
            --short-name)
                if [ $((i + 1)) -gt $# ]; then
                    echo 'Error: --short-name requires a value' >&2
                    exit 1
                fi
                i=$((i + 1))
                local next_arg="${!i}"
                if [[ "$next_arg" == --* ]]; then
                    echo 'Error: --short-name requires a value' >&2
                    exit 1
                fi
                short_name="$next_arg"
                ;;
            --number)
                if [ $((i + 1)) -gt $# ]; then
                    echo 'Error: --number requires a value' >&2
                    exit 1
                fi
                i=$((i + 1))
                local next_arg="${!i}"
                if [[ "$next_arg" == --* ]]; then
                    echo 'Error: --number requires a value' >&2
                    exit 1
                fi
                branch_number="$next_arg"
                ;;
            --help|-h) 
                echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>"
                echo ""
                echo "Options:"
                echo "  --json              Output in JSON format"
                echo "  --short-name <name> Provide a custom short name (2-4 words) for the branch"
                echo "  --number N          Specify branch number manually (overrides auto-detection)"
                echo "  --help, -h          Show this help message"
                echo ""
                echo "Examples:"
                echo "  $0 'Add user authentication system' --short-name 'user-auth'"
                echo "  $0 'Implement OAuth2 integration for API' --number 5"
                return 0
                ;;
            *)
                args+=("$arg") 
                ;;
        esac
        i=$((i + 1))
    done

    local feature_description="${args[*]}"
    if [ -z "$feature_description" ]; then
        echo "Usage: $0 [--json] [--short-name <name>] [--number N] <feature_description>" >&2
        exit 1
    fi

    local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    local repo_root
    local has_git

    if git rev-parse --show-toplevel >/dev/null 2>&1; then
        repo_root=$(git rev-parse --show-toplevel)
        has_git=true
    else
        repo_root="$(find_repo_root "$script_dir")"
        if [ -z "$repo_root" ]; then
            echo "Error: Could not determine repository root." >&2
            exit 1
        fi
        has_git=false
    fi

    cd "$repo_root"
    local specs_dir="$repo_root/specs"
    mkdir -p "$specs_dir"

    # Generate branch name suffix
    local branch_suffix
    if [ -n "$short_name" ]; then
        branch_suffix=$(echo "$short_name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//')
    else
        branch_suffix=$(generate_branch_name "$feature_description")
    fi

    # Determine feature number
    local feature_num
    if [ -n "$branch_number" ]; then
        feature_num="$branch_number"
    else
        feature_num=$(check_existing_branches "$branch_suffix" "$specs_dir")
    fi

    local branch_name="${feature_num}-${branch_suffix}"

    # Validate and truncate if necessary
    local max_branch_length=244
    if [ ${#branch_name} -gt $max_branch_length ]; then
        local max_suffix_length=$((max_branch_length - 4))
        local truncated_suffix=$(echo "$branch_suffix" | cut -c1-$max_suffix_length | sed 's/-$//')
        
        local original_branch_name="$branch_name"
        branch_name="${feature_num}-${truncated_suffix}"
        
        >&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
        >&2 echo "[specify] Original: $original_branch_name (${#original_branch_name} bytes)"
        >&2 echo "[specify] Truncated to: $branch_name (${#branch_name} bytes)"
    fi

    if [ "$has_git" = true ]; then
        git checkout -b "$branch_name"
    else
        >&2 echo "[specify] Warning: Git repository not detected; skipped branch creation for $branch_name"
    fi

    local feature_dir="$specs_dir/$branch_name"
    mkdir -p "$feature_dir"

    local template="$repo_root/.specify/templates/spec-template.md"
    local spec_file="$feature_dir/spec.md"
    if [ -f "$template" ]; then cp "$template" "$spec_file"; else touch "$spec_file"; fi

    # Set the SPECIFY_FEATURE environment variable for the current session
    export SPECIFY_FEATURE="$branch_name"

    if $json_mode; then
        printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$branch_name" "$spec_file" "$feature_num"
    else
        echo "BRANCH_NAME: $branch_name"
        echo "SPEC_FILE: $spec_file"
        echo "FEATURE_NUM: $feature_num"
        echo "SPECIFY_FEATURE environment variable set to: $branch_name"
    fi
}

# Execute main function if script is run directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi