#!/usr/bin/env bash
# generate_password
# -----------------
# Genera contraseñas seguras en varios modos: completo (alfanumérico + símbolos),
# solo alfanumérico, passphrase de palabras o PIN numérico.
# Calcula la entropía en bits para cada contraseña generada.
#
# USO (directo):
#   generate_password [full|alpha|passphrase|pin] [longitud] [cantidad]
#
# Depende de: /dev/urandom, python3 (para entropía), shuf (para passphrases)

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../shell/bash_colors.sh"
source "$SCRIPT_DIR/../shell/bash_log.sh"
bash_colors
bash_log_init

# ─── Constantes ───────────────────────────────────────────────────────────────

_GENPW_DEFAULT_LENGTH=16
_GENPW_DEFAULT_COUNT=1
_GENPW_WORDLIST_PATHS=("/usr/share/dict/words" "/usr/dict/words" "/usr/share/dict/american-english")

# ─── Funciones puras ──────────────────────────────────────────────────────────

_genpw_find_wordlist() {
    for path in "${_GENPW_WORDLIST_PATHS[@]}"; do
        [[ -f "$path" ]] && echo "$path" && return
    done
    echo ""
}

_genpw_calc_entropy() {
    local charset_size="$1"
    local length="$2"
    python3 -c "import math; print(f'{math.log2(${charset_size}**${length}):.1f}')" 2>/dev/null || echo "?"
}

# ─── Funciones de generación ──────────────────────────────────────────────────

_genpw_gen_full() {
    local length="$1"
    # Alfanumérico + símbolos (excluye ambiguos: 0OlI1)
    tr -dc 'A-HJ-NP-Za-km-z2-9!@#$%^&*()_+-=[]{}|;:,.<>?' \
        < /dev/urandom | head -c "$length"
    echo
}

_genpw_gen_alpha() {
    local length="$1"
    tr -dc 'A-HJ-NP-Za-km-z2-9' \
        < /dev/urandom | head -c "$length"
    echo
}

_genpw_gen_passphrase() {
    local words="$1"
    local wordlist
    wordlist="$(_genpw_find_wordlist)"

    if [[ -z "$wordlist" ]]; then
        error "generate_password: no se encontró diccionario (sudo apt install wamerican)" >&2
        return 1
    fi

    local phrase=""
    for ((i=0; i<words; i++)); do
        local word
        word="$(shuf -n1 "$wordlist" | tr -dc 'a-z' | head -c 20)"
        [[ ${#word} -lt 3 ]] && { i=$((i-1)); continue; }
        phrase="${phrase}${word}-"
    done
    echo "${phrase%-}"
}

_genpw_gen_pin() {
    local length="$1"
    tr -dc '0-9' < /dev/urandom | head -c "$length"
    echo
}

# ─── Punto de entrada ─────────────────────────────────────────────────────────

generate_password() {
    local mode="${1:-full}"
    local length="${2:-$_GENPW_DEFAULT_LENGTH}"
    local count="${3:-$_GENPW_DEFAULT_COUNT}"

    # Validar que length y count son numéricos
    if ! [[ "$length" =~ ^[0-9]+$ ]] || ! [[ "$count" =~ ^[0-9]+$ ]]; then
        error "generate_password: longitud y cantidad deben ser números enteros positivos" >&2
        return 1
    fi

    local charset_size entropy

    case "$mode" in
        full)
            charset_size=78
            entropy="$(_genpw_calc_entropy $charset_size "$length")"
            info "Contraseñas alfanuméricas + símbolos (longitud: ${length}, entropía: ~${entropy} bits)"
            echo ""
            for ((i=1; i<=count; i++)); do
                _genpw_gen_full "$length"
            done
            ;;
        alpha)
            charset_size=56
            entropy="$(_genpw_calc_entropy $charset_size "$length")"
            info "Contraseñas alfanuméricas (longitud: ${length}, entropía: ~${entropy} bits)"
            echo ""
            for ((i=1; i<=count; i++)); do
                _genpw_gen_alpha "$length"
            done
            ;;
        passphrase)
            info "Passphrases (${length} palabras)"
            echo ""
            for ((i=1; i<=count; i++)); do
                _genpw_gen_passphrase "$length" || return 1
            done
            ;;
        pin)
            charset_size=10
            entropy="$(_genpw_calc_entropy $charset_size "$length")"
            info "PINs numéricos (longitud: ${length}, entropía: ~${entropy} bits)"
            echo ""
            for ((i=1; i<=count; i++)); do
                _genpw_gen_pin "$length"
            done
            ;;
        *)
            error "generate_password: modo no válido '$mode'. Use: full|alpha|passphrase|pin" >&2
            return 1
            ;;
    esac
}

# Ejecutar si se llama directamente
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    generate_password "$@"
fi
