#!/usr/bin/env bash
# tbd_branch_create — crea rama TBD desde master/main actualizado
#
# Uso:
#   tbd_branch_create issue <NNNN> <slug>
#   tbd_branch_create quick <slug>
#
# Opciones especiales:
#   --test   ejecutar suite de tests internos y salir

set -euo pipefail

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

_tbd_detect_base() {
    # Retorna 'master' o 'main' — el primero que exista localmente
    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_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
}

_tbd_pull_rebase() {
    # Hace pull --rebase solo si hay upstream configurado; si no, es no-op.
    local has_upstream
    has_upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo "")
    if [[ -n "$has_upstream" ]]; then
        git pull --rebase
    else
        echo "(sin remote upstream — saltando pull)"
    fi
}

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

tbd_branch_create() {
    local mode="${1:-}"

    if [[ -z "$mode" ]] || [[ "$mode" != "issue" && "$mode" != "quick" ]]; then
        echo "Uso: tbd_branch_create issue <NNNN> <slug>" >&2
        echo "     tbd_branch_create quick <slug>" >&2
        return 1
    fi

    # Verificar repo git
    _tbd_require_git_repo

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

    # Construir nombre de rama segun modo
    local branch_name
    if [[ "$mode" == "issue" ]]; then
        local num="${2:-}"
        local slug="${3:-}"
        if [[ -z "$num" || -z "$slug" ]]; then
            echo "Uso: tbd_branch_create issue <NNNN> <slug>" >&2
            return 1
        fi
        if [[ ! "$num" =~ ^[0-9]{4}$ ]]; then
            echo "ERROR: <NNNN> debe ser exactamente 4 digitos numericos (ej: 0042)." >&2
            return 1
        fi
        if [[ ! "$slug" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
            echo "ERROR: slug debe ser kebab-case ASCII (ej: fix-typo, add-auth)." >&2
            return 1
        fi
        branch_name="issue/${num}-${slug}"
    else
        # quick
        local slug="${2:-}"
        if [[ -z "$slug" ]]; then
            echo "Uso: tbd_branch_create quick <slug>" >&2
            return 1
        fi
        if [[ ! "$slug" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
            echo "ERROR: slug debe ser kebab-case ASCII (ej: fix-typo, update-readme)." >&2
            return 1
        fi
        branch_name="quick/${slug}"
    fi

    # Verificar si la rama ya existe
    if git show-ref --verify --quiet "refs/heads/${branch_name}" 2>/dev/null; then
        echo "ERROR: la rama '${branch_name}' ya existe localmente." >&2
        return 1
    fi

    # Asegurarse de estar en la rama base
    local current
    current=$(git branch --show-current)
    if [[ "$current" != "$base" ]]; then
        echo "Cambiando a ${base}..."
        git checkout "$base"
    fi

    # Verificar working tree limpio
    local dirty
    dirty=$(git status --porcelain)
    if [[ -n "$dirty" ]]; then
        echo "ERROR: working tree dirty. Commit o stash los cambios antes de crear la rama." >&2
        return 1
    fi

    # Actualizar base desde remote si hay upstream
    echo "Actualizando ${base}..."
    _tbd_pull_rebase

    # Crear la rama
    git checkout -b "$branch_name"

    echo "Rama '${branch_name}' creada desde ${base} actualizada."
    return 0
}

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

_tbd_branch_create_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 clonado (master)
    # ---------------------------------------------------------------------------
    local tmproot
    tmproot=$(mktemp -d)

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

    git -c init.defaultBranch=master init --bare -q "$bare"
    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: rama issue valida
    # ---------------------------------------------------------------------------
    (
        cd "$work"
        tbd_branch_create issue 0042 add-auth
    ) > /dev/null 2>&1
    local result
    result=$(cd "$work" && git branch --show-current)
    _assert_eq "issue branch created" "issue/0042-add-auth" "$result"

    # Volver a master
    (cd "$work" && git checkout -q master)

    # ---------------------------------------------------------------------------
    # Test: rama quick valida
    # ---------------------------------------------------------------------------
    (
        cd "$work"
        tbd_branch_create quick fix-typo
    ) > /dev/null 2>&1
    result=$(cd "$work" && git branch --show-current)
    _assert_eq "quick branch created" "quick/fix-typo" "$result"

    (cd "$work" && git checkout -q master)

    # ---------------------------------------------------------------------------
    # Test: numero de issue invalido (3 digitos)
    # ---------------------------------------------------------------------------
    _assert_exit "issue number must be 4 digits" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_create issue 042 fix
    "

    # ---------------------------------------------------------------------------
    # Test: slug invalido (mayusculas)
    # ---------------------------------------------------------------------------
    _assert_exit "slug must be kebab-case" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_create issue 0001 Fix-Typo
    "

    # ---------------------------------------------------------------------------
    # Test: modo invalido
    # ---------------------------------------------------------------------------
    _assert_exit "invalid mode exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_create hotfix my-slug
    "

    # ---------------------------------------------------------------------------
    # Test: sin argumentos
    # ---------------------------------------------------------------------------
    _assert_exit "no args exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_create
    "

    # ---------------------------------------------------------------------------
    # Test: working tree dirty → error
    # ---------------------------------------------------------------------------
    echo "dirty" > "$work/dirty.txt"
    _assert_exit "dirty tree exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_create quick clean-slug
    "
    rm -f "$work/dirty.txt"

    # ---------------------------------------------------------------------------
    # Test: rama ya existe → error
    # ---------------------------------------------------------------------------
    (cd "$work" && git checkout -q -b issue/0099-existing && git checkout -q master)
    _assert_exit "existing branch exits 1" 1 bash -c "
        cd '$work'
        source '${BASH_SOURCE[0]}'
        tbd_branch_create issue 0099 existing
    "

    # ---------------------------------------------------------------------------
    # Test: funciona con 'main' como rama base
    # ---------------------------------------------------------------------------
    local bare2="$tmproot/remote2.git"
    local work2="$tmproot/work2"
    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
        tbd_branch_create quick use-main
    ) > /dev/null 2>&1
    result=$(cd "$work2" && git branch --show-current)
    _assert_eq "works with main as base" "quick/use-main" "$result"

    # ---------------------------------------------------------------------------
    # Cleanup y resultado
    # ---------------------------------------------------------------------------
    rm -rf "$tmproot"

    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_create_tests
    else
        tbd_branch_create "$@"
    fi
fi
