#!/bin/bash
# ClaudeTools Gitea Operations — bulletproof git/gitea helpers for the fleet
# Extracted patterns from sync.sh into reusable commands

set -e

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

# --- Helper functions (extracted from sync.sh) ---

get_repo_root() {
    local IDENTITY_PATH=""
    for candidate in "$HOME/.claude/identity.json" ".claude/identity.json"; do
        if [ -f "$candidate" ]; then
            IDENTITY_PATH="$candidate"
            break
        fi
    done

    local REPO_ROOT=""
    if [ -n "$IDENTITY_PATH" ] && command -v jq >/dev/null 2>&1; then
        REPO_ROOT=$(jq -r '.claudetools_root // empty' "$IDENTITY_PATH" 2>/dev/null)
    fi

    if [ -z "$REPO_ROOT" ]; then
        REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
    fi

    if [ -z "$REPO_ROOT" ] || [ ! -d "$REPO_ROOT/.git" ]; then
        echo -e "${RED}[ERROR]${NC} Cannot locate git repo. Add 'claudetools_root' to identity.json" >&2
        exit 3
    fi

    echo "$REPO_ROOT"
}

load_identity() {
    local REPO_ROOT="$1"

    if [ ! -f "$REPO_ROOT/.claude/identity.json" ]; then
        echo -e "${RED}[ERROR]${NC} identity.json not found" >&2
        exit 2
    fi

    # Detect Python
    local PYTHON=""
    if command -v jq >/dev/null 2>&1; then
        PYTHON=$(jq -r '.python.command // empty' "$REPO_ROOT/.claude/identity.json" 2>/dev/null)
    fi

    if [ -z "$PYTHON" ]; then
        for candidate in py python3 python; do
            if command -v "$candidate" >/dev/null 2>&1; then
                if "$candidate" -c "import sys; sys.exit(0)" >/dev/null 2>&1; then
                    PYTHON="$candidate"
                    break
                fi
            fi
        done
    fi

    if [ -z "$PYTHON" ]; then
        echo -e "${RED}[ERROR]${NC} No Python interpreter found" >&2
        exit 2
    fi

    # Load identity fields
    USER_DISPLAY=$($PYTHON -c "import json; d=json.load(open('$REPO_ROOT/.claude/identity.json')); print(d.get('full_name', d.get('user','unknown')))" 2>/dev/null || echo "unknown")
    USER_EMAIL=$($PYTHON -c "import json; d=json.load(open('$REPO_ROOT/.claude/identity.json')); print(d.get('email',''))" 2>/dev/null || echo "")

    export PYTHON USER_DISPLAY USER_EMAIL
}

reconcile_git_identity() {
    local want_name="$1" want_email="$2"

    [ "$want_name" = "unknown" ] && return 0

    if [ -n "$want_name" ]; then
        local cur=$(git config user.name 2>/dev/null || true)
        if [ "$cur" != "$want_name" ]; then
            echo -e "${YELLOW}[WARNING]${NC} git user.name '$cur' -> '$want_name'" >&2
            git config user.name "$want_name"
        fi
    fi

    if [ -n "$want_email" ]; then
        local cur=$(git config user.email 2>/dev/null || true)
        if [ "$cur" != "$want_email" ]; then
            echo -e "${YELLOW}[WARNING]${NC} git user.email '$cur' -> '$want_email'" >&2
            git config user.email "$want_email"
        fi
    fi
}

resolve_submodule_collisions() {
    [ -f ".gitmodules" ] || return 1
    local moved=0 subpath target untracked stamp dest
    local subpaths=()
    stamp=$(date -u "+%Y%m%dT%H%M%SZ")

    while read -r p; do
        [ -n "$p" ] && subpaths+=("$p")
    done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$' 2>/dev/null | awk '{print $2}')

    for subpath in "${subpaths[@]}"; do
        [ -e "$subpath/.git" ] || continue
        target=$(git ls-tree HEAD -- "$subpath" 2>/dev/null | awk '$2=="commit"{print $3}')
        [ -n "$target" ] || continue
        git -C "$subpath" cat-file -e "$target" 2>/dev/null || continue

        while IFS= read -r -d '' untracked; do
            git -C "$subpath" cat-file -e "${target}:${untracked}" 2>/dev/null || continue
            dest="${untracked}.synced-aside-${stamp}"
            if mv "$subpath/$untracked" "$subpath/$dest" 2>/dev/null; then
                echo -e "${YELLOW}[WARNING]${NC} ${subpath}: preserved colliding '$untracked' as '$dest'" >&2
                moved=1
            fi
        done < <(git -C "$subpath" ls-files --others --exclude-standard -z 2>/dev/null)
    done

    [ "$moved" -eq 1 ] && return 0 || return 1
}

inject_credentials() {
    # Inject parent HTTPS credentials to submodule URLs
    local PARENT_URL="$(git config --get remote.origin.url)"
    local CRED_HOST=""

    case "$PARENT_URL" in
        https://*@*)
            CRED_HOST="$(printf '%s' "$PARENT_URL" | sed -E 's#^(https://[^/]+)/.*#\1#')"
            ;;
    esac

    [ -z "$CRED_HOST" ] && return 0

    while read -r pkey ppath; do
        [ -z "$ppath" ] && continue
        local name="$(printf '%s' "$pkey" | sed -E 's#^submodule\.(.*)\.path$#\1#')"
        local gm_url="$(git config --file .gitmodules --get "submodule.${name}.url")"

        case "$gm_url" in
            https://*)
                local sub_path="$(printf '%s' "$gm_url" | sed -E 's#^https://[^/]+(/.*)#\1#')"
                git config "submodule.${name}.url" "${CRED_HOST}${sub_path}"
                ;;
        esac
    done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$' 2>/dev/null)
}

# --- Commands ---

cmd_submodule_init() {
    local target_path="$1"

    if [ ! -f ".gitmodules" ]; then
        echo -e "${GREEN}[OK]${NC} No submodules configured"
        return 0
    fi

    inject_credentials

    local count=0
    while read -r pkey ppath; do
        [ -z "$ppath" ] && continue

        if [ -n "$target_path" ] && [ "$ppath" != "$target_path" ]; then
            continue
        fi

        local name="$(printf '%s' "$pkey" | sed -E 's#^submodule\.(.*)\.path$#\1#')"

        echo -e "${CYAN}[INFO]${NC} Initializing $ppath..."
        git submodule init -- "$ppath" >/dev/null 2>&1

        set +e
        git submodule update --init -- "$ppath" >/dev/null 2>&1
        local rc=$?
        set -e

        if [ $rc -ne 0 ]; then
            if resolve_submodule_collisions; then
                git submodule update --init -- "$ppath" >/dev/null 2>&1
            fi
        fi

        if [ -d "$ppath" ] && [ "$USER_DISPLAY" != "unknown" ]; then
            (cd "$ppath" && reconcile_git_identity "$USER_DISPLAY" "$USER_EMAIL") || true
        fi

        count=$((count + 1))
    done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$')

    echo -e "${GREEN}[OK]${NC} Initialized $count submodule(s)"
}

cmd_submodule_update() {
    local target_path="$1"

    if [ ! -f ".gitmodules" ]; then
        echo -e "${GREEN}[OK]${NC} No submodules"
        return 0
    fi

    if [ -n "$target_path" ]; then
        echo -e "${CYAN}[INFO]${NC} Updating $target_path to pinned commit..."
        set +e
        local out=$(git submodule update --init -- "$target_path" 2>&1)
        local rc=$?
        set -e

        if [ $rc -ne 0 ]; then
            if resolve_submodule_collisions; then
                out=$(git submodule update --init -- "$target_path" 2>&1)
                rc=$?
            fi

            if [ $rc -ne 0 ]; then
                echo "$out" | grep -v '^$'
                echo -e "${RED}[ERROR]${NC} Submodule update failed"
                return 1
            fi
        fi

        echo -e "${GREEN}[OK]${NC} Updated $target_path"
    else
        echo -e "${CYAN}[INFO]${NC} Updating all submodules..."
        set +e
        local out=$(git submodule update --init --recursive 2>&1)
        local rc=$?
        set -e

        if [ $rc -ne 0 ]; then
            if resolve_submodule_collisions; then
                out=$(git submodule update --init --recursive 2>&1)
                rc=$?
            fi

            if [ $rc -ne 0 ]; then
                echo "$out" | grep -v '^$'
                echo -e "${YELLOW}[WARNING]${NC} Some submodules failed to update"
            else
                echo -e "${GREEN}[OK]${NC} Updated all submodules (resolved collisions)"
            fi
        else
            echo -e "${GREEN}[OK]${NC} Updated all submodules"
        fi
    fi
}

cmd_submodule_sync() {
    local target_path="$1"

    if [ ! -f ".gitmodules" ]; then
        echo -e "${GREEN}[OK]${NC} No submodules"
        return 0
    fi

    echo -e "${CYAN}[INFO]${NC} Syncing submodules to remote tips (fetch + ff-merge)..."

    if [ -n "$target_path" ]; then
        if [ ! -d "$target_path" ]; then
            echo -e "${RED}[ERROR]${NC} Submodule not initialized: $target_path"
            return 1
        fi

        (
            cd "$target_path"
            git fetch origin --quiet 2>/dev/null
            git checkout main --quiet 2>/dev/null || git checkout master --quiet 2>/dev/null
            git merge --ff-only origin/main --quiet 2>/dev/null || \
                git merge --ff-only origin/master --quiet 2>/dev/null
        )

        echo -e "${GREEN}[OK]${NC} Synced $target_path"
    else
        set +e
        git submodule foreach --quiet '
            git fetch origin --quiet 2>/dev/null
            git checkout main --quiet 2>/dev/null || git checkout master --quiet 2>/dev/null
            git merge --ff-only origin/main --quiet 2>/dev/null || \
                git merge --ff-only origin/master --quiet 2>/dev/null
        ' 2>/dev/null
        set -e

        echo -e "${GREEN}[OK]${NC} Synced all submodules to remote tips"
    fi
}

cmd_submodule_status() {
    if [ ! -f ".gitmodules" ]; then
        echo -e "${GREEN}[OK]${NC} No submodules"
        return 0
    fi

    echo -e "${CYAN}Submodule Status:${NC}"
    git submodule status | while IFS= read -r line; do
        # Format: {status_char}{40_char_hash} {path} ({optional_description})
        local status_char="${line:0:1}"
        local hash_and_rest="${line:1}"
        local path_and_desc="${hash_and_rest:41}"  # Skip 40-char hash + 1 space

        case "$status_char" in
            "-") echo -e "  ${YELLOW}[-]${NC} $path_and_desc (not initialized)" ;;
            "+") echo -e "  ${YELLOW}[+]${NC} $path_and_desc (modified/ahead)" ;;
            "U") echo -e "  ${RED}[U]${NC} $path_and_desc (merge conflict)" ;;
            " ") echo -e "  ${GREEN}[OK]${NC} $path_and_desc" ;;
            *) echo -e "  ${CYAN}[?]${NC} $path_and_desc (unknown status: $status_char)" ;;
        esac
    done
}

cmd_submodule_fix() {
    local target_path="$1"

    echo -e "${CYAN}[INFO]${NC} Running submodule diagnostics..."

    if [ ! -f ".gitmodules" ]; then
        echo -e "${GREEN}[OK]${NC} No submodules"
        return 0
    fi

    local fixed=0

    # Check for missing/uninitialized submodules
    while read -r pkey ppath; do
        [ -z "$ppath" ] && continue

        if [ -n "$target_path" ] && [ "$ppath" != "$target_path" ]; then
            continue
        fi

        if [ ! -d "$ppath/.git" ]; then
            echo -e "${YELLOW}[FIX]${NC} Initializing missing submodule: $ppath"
            cmd_submodule_init "$ppath"
            fixed=1
        else
            # Check for detached HEAD
            if ! git -C "$ppath" symbolic-ref HEAD >/dev/null 2>&1; then
                echo -e "${YELLOW}[FIX]${NC} Reattaching detached HEAD in $ppath"
                (
                    cd "$ppath"
                    git checkout main 2>/dev/null || git checkout master 2>/dev/null || true
                )
                fixed=1
            fi

            # Check for uncommitted changes
            if [ -n "$(git -C "$ppath" status --porcelain)" ]; then
                echo -e "${YELLOW}[WARNING]${NC} $ppath has uncommitted changes (not auto-fixed)"
            fi
        fi
    done < <(git config --file .gitmodules --get-regexp '^submodule\..*\.path$')

    # Try update to resolve pointer mismatches
    if cmd_submodule_update "$target_path" 2>/dev/null; then
        fixed=1
    fi

    if [ $fixed -eq 1 ]; then
        echo -e "${GREEN}[OK]${NC} Fixed submodule issues"
    else
        echo -e "${GREEN}[OK]${NC} No issues found"
    fi
}

cmd_status() {
    local verbose="$1"

    echo -e "${CYAN}Repository Status:${NC}"
    git status --short

    if [ "$verbose" = "--verbose" ]; then
        echo ""
        cmd_submodule_status
    fi
}

cmd_health() {
    echo -e "${CYAN}Running health check...${NC}"
    echo ""

    local issues=0

    # Check identity
    if [ "$USER_DISPLAY" = "unknown" ]; then
        echo -e "${RED}[ERROR]${NC} identity.json unreadable"
        issues=$((issues + 1))
    else
        echo -e "${GREEN}[OK]${NC} Identity: $USER_DISPLAY <$USER_EMAIL>"
    fi

    # Check git config
    local cfg_name=$(git config user.name || echo "")
    local cfg_email=$(git config user.email || echo "")

    if [ "$cfg_name" != "$USER_DISPLAY" ] || [ "$cfg_email" != "$USER_EMAIL" ]; then
        echo -e "${YELLOW}[WARNING]${NC} Git config doesn't match identity.json"
        issues=$((issues + 1))
    else
        echo -e "${GREEN}[OK]${NC} Git identity matches"
    fi

    # Check for uncommitted changes
    if [ -n "$(git status --porcelain)" ]; then
        echo -e "${YELLOW}[INFO]${NC} Uncommitted changes present"
    else
        echo -e "${GREEN}[OK]${NC} Working tree clean"
    fi

    # Check submodules
    if [ -f ".gitmodules" ]; then
        local sub_issues=0
        while read -r line; do
            local status="${line:0:1}"
            case "$status" in
                "-"|"U") sub_issues=$((sub_issues + 1)) ;;
            esac
        done < <(git submodule status 2>/dev/null)

        if [ $sub_issues -gt 0 ]; then
            echo -e "${YELLOW}[WARNING]${NC} $sub_issues submodule(s) need attention"
            issues=$((issues + 1))
        else
            echo -e "${GREEN}[OK]${NC} All submodules healthy"
        fi
    fi

    # Check remote connectivity
    if git ls-remote origin HEAD >/dev/null 2>&1; then
        echo -e "${GREEN}[OK]${NC} Remote reachable"
    else
        echo -e "${RED}[ERROR]${NC} Cannot reach remote"
        issues=$((issues + 1))
    fi

    echo ""
    if [ $issues -eq 0 ]; then
        echo -e "${GREEN}[SUCCESS]${NC} Repository healthy"
        return 0
    else
        echo -e "${YELLOW}[WARNING]${NC} $issues issue(s) found"
        return 1
    fi
}

cmd_fetch() {
    local recurse="$1"

    echo -e "${CYAN}[INFO]${NC} Fetching from origin..."

    if [ "$recurse" = "--recurse" ]; then
        git fetch origin --recurse-submodules
    else
        git fetch origin --no-recurse-submodules
    fi

    echo -e "${GREEN}[OK]${NC} Fetch complete"
}

cmd_pull() {
    local recurse="$1"

    echo -e "${CYAN}[INFO]${NC} Pulling from origin (rebase)..."

    local flags="--rebase"
    [ "$recurse" != "--recurse" ] && flags="$flags --no-recurse-submodules"

    if git pull origin main $flags; then
        echo -e "${GREEN}[OK]${NC} Pull successful"

        if [ "$recurse" != "--recurse" ]; then
            cmd_submodule_update
        fi
    else
        echo -e "${RED}[ERROR]${NC} Pull failed (likely conflicts)"
        return 1
    fi
}

cmd_push() {
    echo -e "${CYAN}[INFO]${NC} Pushing to origin..."

    if git push origin main; then
        echo -e "${GREEN}[OK]${NC} Push successful"
    else
        echo -e "${RED}[ERROR]${NC} Push failed"
        return 1
    fi
}

cmd_commit() {
    local msg="$1"

    if [ -z "$msg" ]; then
        echo -e "${RED}[ERROR]${NC} Commit message required"
        return 1
    fi

    if git diff-index --quiet --cached HEAD -- 2>/dev/null; then
        echo -e "${YELLOW}[INFO]${NC} No staged changes to commit"
        return 0
    fi

    git commit -m "$msg"
    echo -e "${GREEN}[OK]${NC} Committed"
}

cmd_verify_identity() {
    reconcile_git_identity "$USER_DISPLAY" "$USER_EMAIL"
    echo -e "${GREEN}[OK]${NC} Identity verified and updated if needed"
}

cmd_inject_creds() {
    inject_credentials
    echo -e "${GREEN}[OK]${NC} Credentials injected to submodules"
}

# --- Main ---

COMMAND="${1:-}"
shift || true

# Change to repo root
REPO_ROOT=$(get_repo_root)
cd "$REPO_ROOT"

# Load identity
load_identity "$REPO_ROOT"

case "$COMMAND" in
    submodule)
        SUBCOMMAND="${1:-}"
        shift || true
        case "$SUBCOMMAND" in
            init) cmd_submodule_init "$@" ;;
            update) cmd_submodule_update "$@" ;;
            sync) cmd_submodule_sync "$@" ;;
            status) cmd_submodule_status ;;
            fix) cmd_submodule_fix "$@" ;;
            *)
                echo "Usage: $0 submodule {init|update|sync|status|fix} [PATH]"
                exit 1
                ;;
        esac
        ;;
    status) cmd_status "$@" ;;
    health) cmd_health ;;
    fetch) cmd_fetch "$@" ;;
    pull) cmd_pull "$@" ;;
    push) cmd_push ;;
    commit) cmd_commit "$@" ;;
    verify-identity) cmd_verify_identity ;;
    inject-creds) cmd_inject_creds ;;
    *)
        echo "Usage: $0 {submodule|status|health|fetch|pull|push|commit|verify-identity|inject-creds}"
        exit 1
        ;;
esac
