#!/usr/bin/env bash
# tbd_branch_finish — integra rama TBD a master/main y publica
#
# Uso:
#   tbd_branch_finish [<merge_title>]
#
# Opciones especiales:
#   --test   ejecutar suite de tests internos y salir

set -euo pipefail

# ---------------------------------------------------------------------------
# helpers
# ---------------------------------------------------------------------------

_tbd_finish_detect_base() {
    if git show-ref --verify --quiet refs/heads/master 2>/dev/null; then
        echo "master"
    elif git show-ref --verify --quiet refs/heads/main 2>/dev/null; then
        echo "main"
    else
        echo ""
    fi
}

_tbd_finish_require_git_repo() {
    if ! git rev-parse --git-dir > /dev/null 2>&1; then
        echo "ERROR: el directorio actual no es un repositorio git." >&2
        return 1
    fi
}

# ---------------------------------------------------------------------------
# funcion principal
# ---------------------------------------------------------------------------

tbd_branch_finish() {
    local merge_title="${1:-}"

    # Verificar repo git
    _tbd_finish_require_git_repo

    # Detectar rama actual
    local branch
    branch=$(git branch --show-current)

    # Validar que es una rama TBD (issue/* o quick/*)
    if [[ "$branch" != issue/* && "$branch" != quick/* ]]; then
        if [[ "$branch" == "master" || "$branch" == "main" ]]; then
            echo "ERROR: ya estas en ${branch}, nada que mergear." >&2
            return 1
        else
            echo "ERROR: la rama actual '${branch}' no es una rama TBD (issue/* o quick/*)." >&2
            return 1
        fi
    fi

    # Verificar working tree limpio
    local dirty
    dirty=$(git status --porcelain)
    if [[ -n "$dirty" ]]; then
        echo "ERROR: hay cambios sin commitear. Haz commit antes de mergear." >&2
        return 1
    fi

    # Detectar rama base
    local base
    base=$(_tbd_finish_detect_base)
    if [[ -z "$base" ]]; then
        echo "ERROR: no se encontro rama 'master' ni 'main' en el repo local." >&2
        return 1
    fi

    # Componer titulo del merge commit
    local title
    if [[ -n "$merge_title" ]]; then
        title="merge: ${branch} — ${merge_title}"
    else
        title="merge: ${branch}"
    fi

    # Cambiar a base y actualizar
    echo "Cambiando a ${base}..."
    git checkout "$base"

    echo "Actualizando ${base}..."
    git pull --rebase

    # Merge --no-ff
    echo "Mergeando ${branch} en ${base}..."
    local merge_exit=0
    git merge --no-ff "$branch" -m "$title" || merge_exit=$?

    if [[ $merge_exit -ne 0 ]]; then
        echo "merge conflict: resolver manualmente y continuar (git add + git commit)." >&2
        return 2
    fi

    # Push
    echo "Publicando ${base}..."
    local push_exit=0
    git push || push_exit=$?
    if [[ $push_exit -ne 0 ]]; then
        echo "ERROR: git push fallo (exit ${push_exit}). La rama '${branch}' NO fue eliminada." >&2
        return 1
    fi

    # Eliminar rama local
    git branch -d "$branch"

    echo "Rama '${branch}' integrada a ${base} y publicada. Rama local eliminada."
    return 0
}

# ---------------------------------------------------------------------------
# modo --test
# ---------------------------------------------------------------------------

_tbd_branch_finish_tests() {
    local PASS=0
    local FAIL=0

    _assert_eq() {
        local name="$1" expected="$2" got="$3"
        if [[ "$expected" == "$got" ]]; then
            echo "PASS: $name"
            PASS=$((PASS + 1))
        else
            echo "FAIL: $name — expected '${expected}', got '${got}'"
            FAIL=$((FAIL + 1))
        fi
    }

    _assert_exit() {
        local name="$1" expected_exit="$2"
        shift 2
        local got_exit=0
        "$@" > /dev/null 2>&1 || got_exit=$?
        if [[ "$expected_exit" == "$got_exit" ]]; then
            echo "PASS: $name (exit ${got_exit})"
            PASS=$((PASS + 1))
        else
            echo "FAIL: $name — expected exit ${expected_exit}, got ${got_exit}"
            FAIL=$((FAIL + 1))
        fi
    }

    # ---------------------------------------------------------------------------
    # Setup: bare remote + repo de trabajo
    # ---------------------------------------------------------------------------
    local tmpdir
    tmpdir=$(mktemp -d)
    trap "rm -rf '$tmpdir'" EXIT

    local bare="$tmpdir/remote.git"
    local work="$tmpdir/work"

    # Crear remote bare
    git -c init.defaultBranch=master init --bare -q "$bare"

    # Clonar para tener origin
    git clone -q "$bare" "$work"
    (
        cd "$work"
        git config user.email "test@test.com"
        git config user.name "Test"
        echo "init" > README.md
        git add README.md
        git commit -q -m "chore: init"
        git push -q -u origin master
    )

    # ---------------------------------------------------------------------------
    # Test: merge issue branch sin titulo
    # ---------------------------------------------------------------------------
    (
        cd "$work"
        git checkout -q -b issue/0001-add-feature
        echo "feature" > feature.txt
        git add feature.txt
        git commit -q -m "feat: add feature"
    )

    local finish_exit=0
    (
        cd "$work"
        tbd_branch_finish
    ) > /dev/null 2>&1 || finish_exit=$?

    local current
    current=$(cd "$work" && git branch --show-current)
    _assert_eq "finish lands on base branch" "master" "$current"

    local branch_gone=0
    (cd "$work" && git show-ref --verify --quiet refs/heads/issue/0001-add-feature) && branch_gone=1 || branch_gone=0
    _assert_eq "issue branch deleted locally" "0" "$branch_gone"

    _assert_eq "finish exits 0" "0" "$finish_exit"

    # Verificar merge commit en remote
    local remote_log
    remote_log=$(cd "$work" && git log --oneline -2 origin/master)
    local has_merge=0
    [[ "$remote_log" == *"merge: issue/0001-add-feature"* ]] && has_merge=1 || has_merge=0
    _assert_eq "merge commit pushed to remote" "1" "$has_merge"

    # ---------------------------------------------------------------------------
    # Test: merge quick branch con titulo
    # ---------------------------------------------------------------------------
    (
        cd "$work"
        git checkout -q -b quick/fix-typo
        echo "fix" > fix.txt
        git add fix.txt
        git commit -q -m "fix: typo"
    )

    (
        cd "$work"
        tbd_branch_finish "corregir typo en README"
    ) > /dev/null 2>&1

    current=$(cd "$work" && git branch --show-current)
    _assert_eq "quick branch finish lands on master" "master" "$current"

    remote_log=$(cd "$work" && git log --oneline -2 origin/master)
    local has_title=0
    [[ "$remote_log" == *"merge: quick/fix-typo — corregir typo en README"* ]] && has_title=1 || has_title=0
    _assert_eq "merge title included in commit" "1" "$has_title"

    # ---------------------------------------------------------------------------
    # Test: dirty tree → exit 1
    # ---------------------------------------------------------------------------
    (
        cd "$work"
        git checkout -q -b quick/dirty-test
    )
    echo "dirty" > "$work/dirty.txt"

    _assert_exit "dirty tree exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_finish
    "
    rm -f "$work/dirty.txt"
    (cd "$work" && git checkout -q master)
    (cd "$work" && git branch -D quick/dirty-test 2>/dev/null || true)

    # ---------------------------------------------------------------------------
    # Test: ya en master → exit 1
    # ---------------------------------------------------------------------------
    _assert_exit "on master exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_finish
    "

    # ---------------------------------------------------------------------------
    # Test: rama no TBD → exit 1
    # ---------------------------------------------------------------------------
    (cd "$work" && git checkout -q -b feature/non-tbd 2>/dev/null)
    _assert_exit "non-TBD branch exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_finish
    "
    (cd "$work" && git checkout -q master && git branch -D feature/non-tbd 2>/dev/null || true)

    # ---------------------------------------------------------------------------
    # Test: funciona con 'main' como rama base
    # ---------------------------------------------------------------------------
    local tmpdir2
    tmpdir2=$(mktemp -d)
    local bare2="$tmpdir2/remote.git"
    local work2="$tmpdir2/work"
    git -c init.defaultBranch=main init --bare -q "$bare2"
    git clone -q "$bare2" "$work2"
    (
        cd "$work2"
        git config user.email "test@test.com"
        git config user.name "Test"
        echo "init" > README.md
        git add README.md
        git commit -q -m "chore: init"
        git push -q -u origin main
        git checkout -q -b quick/use-main
        echo "x" > x.txt
        git add x.txt
        git commit -q -m "feat: x"
        tbd_branch_finish
    ) > /dev/null 2>&1
    current=$(cd "$work2" && git branch --show-current)
    _assert_eq "works with main as base" "main" "$current"
    rm -rf "$tmpdir2"

    echo "---"
    echo "Results: ${PASS} passed, ${FAIL} failed"
    [[ $FAIL -eq 0 ]] || exit 1
}

# ---------------------------------------------------------------------------
# entry point
# ---------------------------------------------------------------------------

if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
    if [[ "${1:-}" == "--test" ]]; then
        _tbd_branch_finish_tests
    else
        tbd_branch_finish "$@"
    fi
fi
