#!/bin/bash

# Set or resolve the project version.
#
# In the repo, the version is kept WITHOUT a pre-release number, e.g.
# "0.1.0-dev". The full version (e.g. "0.1.0-dev.1138") is only materialized
# during the release process, so there are no "bump version" commits.
#
# Usage:
#   ./version <version>          Set an explicit version everywhere (e.g. 0.1.0-dev.1138)
#   ./version --from=commits     Compute N from git commit count, stamp 0.1.0-dev.N
#   ./version --from=tag         Compute N from the latest matching git tag + 1, stamp 0.1.0-dev.N
#   ./version --resolve [--from=commits|tag]
#                                Print the resolved full version to stdout and exit
#                                (does not modify any files). Defaults to --from=commits.
#   ./version                    Equivalent to --from=commits (stamp files)
#
# The base version (everything before the pre-release number) is read from
# build.zig.zon and may be either numberless ("0.1.0-dev") or already
# numbered ("0.1.0-dev.123") — both are handled.

BUILD_ZON_FILE="build.zig.zon"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BUILD_ZON_PATH="$PROJECT_ROOT/$BUILD_ZON_FILE"

if [ ! -f "$BUILD_ZON_PATH" ]; then
    echo "Error: $BUILD_ZON_FILE not found at $BUILD_ZON_PATH" >&2
    exit 1
fi

# Extract current version (.version field only, not .jsglue_version etc.)
CURRENT_VERSION=$(grep -E '^\s*\.version\s*=' "$BUILD_ZON_PATH" | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$CURRENT_VERSION" ]; then
    echo "Error: Could not find version in $BUILD_ZON_FILE" >&2
    exit 1
fi


EXPLICIT_VERSION=""
FROM="commits"
RESOLVE_ONLY=0

for arg in "$@"; do
    case "$arg" in
        --resolve)        RESOLVE_ONLY=1 ;;
        --from=commits)   FROM="commits" ;;
        --from=tag)       FROM="tag" ;;
        --commit)         FROM="commits" ;;  # backwards-compatible alias
        --from=*)
            echo "Error: unknown --from value: ${arg#--from=} (use commits|tag)" >&2
            exit 1
            ;;
        --*)
            echo "Error: unknown flag: $arg" >&2
            exit 1
            ;;
        *)
            EXPLICIT_VERSION="$arg" ;;
    esac
done

# Compute the base (version without the pre-release number)

# Strip a trailing ".<number>" pre-release counter if present.
#   0.1.0-dev      -> 0.1.0-dev
#   0.1.0-dev.123  -> 0.1.0-dev
#   0.1.0          -> 0.1.0   (no -dev, left as-is)
BASE_VERSION=$(echo "$CURRENT_VERSION" | sed -E 's/(-[a-zA-Z]+)\.[0-9]+$/\1/')

# Resolve the new full version

if [ -n "$EXPLICIT_VERSION" ]; then
    NEW_VERSION="$EXPLICIT_VERSION"
else
    case "$FROM" in
        commits)
            N=$(git -C "$PROJECT_ROOT" rev-list --count HEAD 2>/dev/null)
            if [ -z "$N" ]; then
                echo "Error: Could not get git commit count" >&2
                exit 1
            fi
            ;;
        tag)
            # Find the highest existing tag matching v<base>.<n> and increment n.
            # E.g. base 0.1.0-dev -> match v0.1.0-dev.*, take the max n, +1.
            ESCAPED_BASE=$(printf '%s' "$BASE_VERSION" | sed -E 's/[.[\*^$()+?{}|]/\\&/g')
            LAST_N=$(git -C "$PROJECT_ROOT" tag --list "v${BASE_VERSION}.*" \
                | sed -E "s/^v${ESCAPED_BASE}\.([0-9]+)$/\1/" \
                | grep -E '^[0-9]+$' \
                | sort -n \
                | tail -1)
            if [ -z "$LAST_N" ]; then
                N=1
            else
                N=$((LAST_N + 1))
            fi
            ;;
    esac
    NEW_VERSION="${BASE_VERSION}.${N}"
fi

# --resolve: just print and exit, touching nothing.
if [ "$RESOLVE_ONLY" -eq 1 ]; then
    echo "$NEW_VERSION"
    exit 0
fi

echo "Version: $CURRENT_VERSION -> $NEW_VERSION"

# Stamp the new version into all version-bearing files

# Match any X.Y.Z[-pre[.N]] version string for in-place replacement.
VERSION_PATTERN='[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z]+(\.[0-9]+)?)?'

# Root build.zig.zon (.version field only)
sed -i.bak -E "/^[[:space:]]*\.version[[:space:]]*=/s/$VERSION_PATTERN/$NEW_VERSION/" "$BUILD_ZON_PATH"
rm -f "$BUILD_ZON_PATH.bak"
echo "Updated $BUILD_ZON_FILE"

# pkg/ziex/build.zig.zon
ZIEX_BUILD_ZON="$PROJECT_ROOT/pkg/ziex/build.zig.zon"
if [ -f "$ZIEX_BUILD_ZON" ]; then
    sed -i.bak -E "/^[[:space:]]*\.version[[:space:]]*=/s/$VERSION_PATTERN/$NEW_VERSION/" "$ZIEX_BUILD_ZON"
    rm -f "$ZIEX_BUILD_ZON.bak"
    echo "Updated pkg/ziex/build.zig.zon"
fi

# pkg/ziex/package.json
ZIEX_PACKAGE_JSON="$PROJECT_ROOT/pkg/ziex/package.json"
if [ -f "$ZIEX_PACKAGE_JSON" ]; then
    sed -i.bak -E "/^[[:space:]]*\"version\"[[:space:]]*:/s/$VERSION_PATTERN/$NEW_VERSION/" "$ZIEX_PACKAGE_JSON"
    rm -f "$ZIEX_PACKAGE_JSON.bak"
    echo "Updated pkg/ziex/package.json"
fi

# ide/zed/extension.toml
ZED_EXTENSION_TOML="$PROJECT_ROOT/ide/zed/extension.toml"
if [ -f "$ZED_EXTENSION_TOML" ]; then
    sed -i.bak -E "/^[[:space:]]*version[[:space:]]*=/s/$VERSION_PATTERN/$NEW_VERSION/" "$ZED_EXTENSION_TOML"
    rm -f "$ZED_EXTENSION_TOML.bak"
    echo "Updated ide/zed/extension.toml"
fi

# ide/vscode/package.json (uses 0.1.N format since VSCode rejects prerelease tags)
VSCODE_PACKAGE_JSON="$PROJECT_ROOT/ide/vscode/package.json"
if [ -f "$VSCODE_PACKAGE_JSON" ]; then
    VSCODE_DEV_NUMBER=$(echo "$NEW_VERSION" | grep -oE '[a-zA-Z]+\.([0-9]+)$' | grep -oE '[0-9]+$')
    if [ -n "$VSCODE_DEV_NUMBER" ]; then
        VSCODE_VERSION="0.1.$VSCODE_DEV_NUMBER"
        sed -i.bak -E "s/\"version\": \"0\\.1\\.[0-9]+\"/\"version\": \"$VSCODE_VERSION\"/" "$VSCODE_PACKAGE_JSON"
        rm -f "$VSCODE_PACKAGE_JSON.bak"
        echo "Updated ide/vscode/package.json -> $VSCODE_VERSION"
    fi
fi

# tree-sitter grammars
for TS in tree-sitter-zx tree-sitter-mdzx; do
    TREE_SITTER_DIR="$PROJECT_ROOT/pkg/$TS"
    if [ -d "$TREE_SITTER_DIR" ]; then
        (cd "$TREE_SITTER_DIR" && tree-sitter version "$NEW_VERSION") 2>/dev/null || true
    fi
done

exit 0
