#!/bin/bash
# pr-merge.sh - Merge pull requests on Gitea or GitHub
# Usage: pr-merge.sh -n PR_NUMBER [-m squash] [-d] [--skip-queue-guard]

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=packages/mosaic/framework/tools/git/detect-platform.sh
source "$SCRIPT_DIR/detect-platform.sh"

# Default values
PR_NUMBER=""
MERGE_METHOD="squash"
DELETE_BRANCH=false
SKIP_QUEUE_GUARD=false
DRY_RUN=false

usage() {
    cat <<EOF
Usage: $(basename "$0") [OPTIONS]

Merge a pull request on the current repository (Gitea or GitHub).

Options:
    -n, --number NUMBER     PR number to merge (required)
    -m, --method METHOD     Merge method: squash only (default: squash)
    -d, --delete-branch     Delete the head branch after merge
        --skip-queue-guard  Skip CI queue guard wait before merge
        --dry-run           Run metadata/login preflight without merging
    -h, --help              Show this help message

Examples:
    $(basename "$0") -n 42                    # Merge PR #42
    $(basename "$0") -n 42 -m squash          # Squash merge
    $(basename "$0") -n 42 -d                 # Squash merge and delete branch
    $(basename "$0") -n 42 --skip-queue-guard # Skip queue guard wait
EOF
    exit "${1:-1}"
}

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -n|--number)
            PR_NUMBER="$2"
            shift 2
            ;;
        -m|--method)
            MERGE_METHOD="$2"
            shift 2
            ;;
        -d|--delete-branch)
            DELETE_BRANCH=true
            shift
            ;;
        --skip-queue-guard)
            SKIP_QUEUE_GUARD=true
            shift
            ;;
        --dry-run)
            DRY_RUN=true
            SKIP_QUEUE_GUARD=true
            shift
            ;;
        -h|--help)
            usage 0
            ;;
        *)
            echo "Unknown option: $1" >&2
            usage
            ;;
    esac
done

if [[ -z "$PR_NUMBER" ]]; then
    echo "Error: PR number is required (-n)" >&2
    usage
fi

if [[ ! "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
    echo "Error: Invalid PR number '$PR_NUMBER'. PR number must contain digits only." >&2
    exit 1
fi

if [[ "$MERGE_METHOD" != "squash" ]]; then
    echo "Error: Mosaic policy enforces squash merge only. Received '$MERGE_METHOD'." >&2
    exit 1
fi

PR_METADATA="$("$SCRIPT_DIR/pr-metadata.sh" -n "$PR_NUMBER")"
BASE_BRANCH="$(printf '%s' "$PR_METADATA" | python3 -c 'import json, sys; print((json.load(sys.stdin).get("baseRefName") or "").strip())')"
if [[ "$BASE_BRANCH" != "main" ]]; then
    echo "Error: Mosaic policy allows merges only for PRs targeting 'main' (found '$BASE_BRANCH')." >&2
    exit 1
fi

if [[ "$SKIP_QUEUE_GUARD" != true ]]; then
    "$SCRIPT_DIR/ci-queue-wait.sh" \
        --purpose merge \
        -B "$BASE_BRANCH" \
        -t "${MOSAIC_CI_QUEUE_TIMEOUT_SEC:-900}" \
        -i "${MOSAIC_CI_QUEUE_POLL_SEC:-15}"
fi

PLATFORM=$(detect_platform)
OWNER=$(get_repo_owner)
REPO=$(get_repo_name)

is_known_tea_empty_identity_failure() {
    local error_file="$1"

    python3 - "$error_file" <<'PY'
import re
import sys

with open(sys.argv[1], encoding="utf-8", errors="replace") as handle:
    error = handle.read()

known_empty_identity = re.search(
    r"user does not exist.*\[.*uid:\s*0,\s*name:\s*\]",
    error,
    flags=re.IGNORECASE | re.DOTALL,
)
raise SystemExit(0 if known_empty_identity else 1)
PY
}

merge_gitea_with_api() {
    local host="$1" api_url token basic_auth body_file raw_code payload
    api_url="https://${host}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}/merge"
    mkdir -p "${AGENT_WORK_ROOT:-${HOME:-/tmp}/mosaic/agent-work}"
    body_file=$(mktemp "${AGENT_WORK_ROOT:-${HOME:-/tmp}/mosaic/agent-work}/pr-merge-api-response.XXXXXX")
    payload='{"Do":"squash"}'

    token=$(get_gitea_token "$host" || true)
    if [[ -n "$token" ]]; then
        raw_code=$(curl -sS -w '%{http_code}' -o "$body_file" \
            -X POST \
            -H "User-Agent: curl/8" \
            -H "Authorization: token $token" \
            -H 'Content-Type: application/json' \
            -d "$payload" \
            "$api_url" || true)
        if [[ "$raw_code" =~ ^2 ]]; then
            rm -f "$body_file"
            return 0
        fi
    fi

    basic_auth=$(get_gitea_basic_auth "$host" || true)
    if [[ -n "$basic_auth" ]]; then
        raw_code=$(curl -sS -w '%{http_code}' -o "$body_file" \
            -X POST \
            -u "$basic_auth" \
            -H "User-Agent: curl/8" \
            -H 'Content-Type: application/json' \
            -d "$payload" \
            "$api_url" || true)
        if [[ "$raw_code" =~ ^2 ]]; then
            rm -f "$body_file"
            return 0
        fi
    fi

    python3 - "${raw_code:-000}" "$body_file" <<'PY' >&2
import json
import sys
code, path = sys.argv[1], sys.argv[2]
try:
    with open(path, encoding="utf-8", errors="replace") as handle:
        raw = handle.read(500)
    data = json.loads(raw) if raw else {}
    message = data.get("message") or data.get("error") or raw or "empty response"
except Exception:
    try:
        message = open(path, encoding="utf-8", errors="replace").read(500) or "empty response"
    except Exception:
        message = "unreadable response"
print(f"Error: Gitea API merge failed with HTTP {code}: {message}")
PY
    rm -f "$body_file"
    return 1
}

if [[ "$DRY_RUN" == true ]]; then
    if [[ "$PLATFORM" == "gitea" ]]; then
        HOST=$(get_remote_host) || {
            echo "Error: Cannot determine host from origin remote URL" >&2
            exit 1
        }
        TEA_LOGIN="$(get_gitea_login_for_host "$HOST" || true)"
        if [[ -n "$TEA_LOGIN" ]]; then
            echo "Dry run: would merge PR #$PR_NUMBER on $HOST with tea login '$TEA_LOGIN' (base=$BASE_BRANCH, method=squash)."
        else
            echo "Dry run: would merge PR #$PR_NUMBER on $HOST with authenticated Gitea API fallback (base=$BASE_BRANCH, method=squash)."
        fi
    else
        echo "Dry run: would merge PR #$PR_NUMBER on $PLATFORM (base=$BASE_BRANCH, method=squash)."
    fi
    exit 0
fi

case "$PLATFORM" in
    github)
        cmd=(gh pr merge "$PR_NUMBER" --squash)
        [[ "$DELETE_BRANCH" == true ]] && cmd+=(--delete-branch)
        "${cmd[@]}"
        ;;
    gitea)
        HOST=$(get_remote_host) || {
            echo "Error: Cannot determine host from origin remote URL" >&2
            exit 1
        }
        TEA_LOGIN="$(get_gitea_login_for_host "$HOST" || true)"

        if [[ -n "$TEA_LOGIN" ]]; then
            mkdir -p "${AGENT_WORK_ROOT:-${HOME:-/tmp}/mosaic/agent-work}"
            TEA_ERROR_FILE=$(mktemp "${AGENT_WORK_ROOT:-${HOME:-/tmp}/mosaic/agent-work}/pr-merge-tea-error.XXXXXX")
            if tea pr merge "$PR_NUMBER" --style squash --repo "$OWNER/$REPO" --login "$TEA_LOGIN" 2> "$TEA_ERROR_FILE"; then
                rm -f "$TEA_ERROR_FILE"
            elif is_known_tea_empty_identity_failure "$TEA_ERROR_FILE"; then
                cat "$TEA_ERROR_FILE" >&2
                echo "Known tea empty identity failure detected; using authenticated Gitea API merge fallback." >&2
                rm -f "$TEA_ERROR_FILE"
                merge_gitea_with_api "$HOST"
            else
                cat "$TEA_ERROR_FILE" >&2
                rm -f "$TEA_ERROR_FILE"
                exit 1
            fi
        else
            echo "No tea login configured for $HOST; using authenticated Gitea API merge fallback." >&2
            merge_gitea_with_api "$HOST"
        fi

        # Delete branch after merge if requested
        if [[ "$DELETE_BRANCH" == true ]]; then
            echo "Note: Branch deletion after merge may need to be done separately with tea" >&2
        fi
        ;;
    *)
        echo "Error: Could not detect git platform" >&2
        exit 1
        ;;
esac

echo "PR #$PR_NUMBER merged successfully"
