#!/usr/bin/env bats

setup_file() {
    PROJECT_ROOT="$(cd "${BATS_TEST_DIRNAME}/.." && pwd)"
    export PROJECT_ROOT
    
    # Create a dummy cache directory for tests
    mkdir -p "${HOME}/.cache/mole"
}

setup() {
    # Default values for tests
    BREW_OUTDATED_COUNT=0
    BREW_FORMULA_OUTDATED_COUNT=0
    BREW_CASK_OUTDATED_COUNT=0
    APPSTORE_UPDATE_COUNT=0
    MACOS_UPDATE_AVAILABLE=false
    MOLE_UPDATE_AVAILABLE=false
    
    # Create a temporary bin directory for mocks
    export MOCK_BIN_DIR="$BATS_TMPDIR/mole-mocks-$$"
    mkdir -p "$MOCK_BIN_DIR"
    export PATH="$MOCK_BIN_DIR:$PATH"
}

teardown() {
    rm -rf "$MOCK_BIN_DIR"
}

read_key() {
    # Default mock: press ESC to cancel
    echo "ESC"
    return 0
}

@test "ask_for_updates returns 1 when no updates available" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"
BREW_OUTDATED_COUNT=0
APPSTORE_UPDATE_COUNT=0
MACOS_UPDATE_AVAILABLE=false
MOLE_UPDATE_AVAILABLE=false
ask_for_updates
EOF

    [ "$status" -eq 1 ]
}

@test "ask_for_updates shows updates and waits for input" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"
BREW_OUTDATED_COUNT=5
BREW_FORMULA_OUTDATED_COUNT=3
BREW_CASK_OUTDATED_COUNT=2
APPSTORE_UPDATE_COUNT=1
MACOS_UPDATE_AVAILABLE=true
MOLE_UPDATE_AVAILABLE=true

read_key() { echo "ESC"; return 0; }

ask_for_updates
EOF

    [ "$status" -eq 1 ]  # ESC cancels
    [[ "$output" == *"Homebrew (5 updates)"* ]]
    [[ "$output" == *"App Store (1 apps)"* ]]
    [[ "$output" == *"macOS system"* ]]
    [[ "$output" == *"Mole"* ]]
}

@test "ask_for_updates accepts Enter when updates exist" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"
BREW_OUTDATED_COUNT=2
BREW_FORMULA_OUTDATED_COUNT=2
read_key() { echo "ENTER"; return 0; }
ask_for_updates
EOF

    [ "$status" -eq 0 ]
    [[ "$output" == *"AVAILABLE UPDATES"* ]]
    [[ "$output" == *"yes"* ]]
}

@test "format_brew_update_label lists formula and cask counts" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"
BREW_OUTDATED_COUNT=5
BREW_FORMULA_OUTDATED_COUNT=3
BREW_CASK_OUTDATED_COUNT=2
format_brew_update_label
EOF

    [ "$status" -eq 0 ]
    [[ "$output" == *"3 formula"* ]]
    [[ "$output" == *"2 cask"* ]]
}

@test "perform_updates handles Homebrew success and Mole update" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"

BREW_FORMULA_OUTDATED_COUNT=1
BREW_CASK_OUTDATED_COUNT=0
MOLE_UPDATE_AVAILABLE=true

FAKE_DIR="$HOME/fake-script-dir"
mkdir -p "$FAKE_DIR/lib/manage"
cat > "$FAKE_DIR/mole" <<'SCRIPT'
#!/usr/bin/env bash
echo "Already on latest version"
SCRIPT
chmod +x "$FAKE_DIR/mole"
SCRIPT_DIR="$FAKE_DIR/lib/manage"

brew_has_outdated() { return 0; }
start_inline_spinner() { :; }
stop_inline_spinner() { :; }
reset_brew_cache() { echo "BREW_CACHE_RESET"; }
reset_mole_cache() { echo "MOLE_CACHE_RESET"; }
has_sudo_session() { return 1; }
ensure_sudo_session() { echo "ensure_sudo_session_called"; return 1; }

brew() {
    if [[ "$1" == "upgrade" ]]; then
        echo "Upgrading formula"
        return 0
    fi
    return 0
}

get_appstore_update_labels() { return 0; }
get_macos_update_labels() { return 0; }

perform_updates
EOF

    [ "$status" -eq 0 ]
    [[ "$output" == *"Homebrew formulae updated"* ]]
    [[ "$output" == *"Already on latest version"* ]]
    [[ "$output" == *"MOLE_CACHE_RESET"* ]]
}

@test "perform_updates skips brew when no outdated packages" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"

BREW_FORMULA_OUTDATED_COUNT=1
BREW_CASK_OUTDATED_COUNT=1
brew_has_outdated() { return 1; }
start_inline_spinner() { :; }
stop_inline_spinner() { :; }

perform_updates
EOF

    [ "$status" -eq 0 ]
    [[ "$output" == *"already up to date"* ]]
}

@test "perform_updates handles App Store fallback logic" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"

APPSTORE_UPDATE_COUNT=2
# Mock getting labels returning empty, triggering fallback
get_appstore_update_labels() { return 0; }

has_sudo_session() { return 0; }
reset_softwareupdate_cache() { :; }

# Mock sudo to check for -a flag (install all)
sudo() {
    if [[ "$1" == "softwareupdate" && "$2" == "-i" && "$3" == "-a" ]]; then
        echo "Installing all updates..."
        return 0
    fi
    echo "Wrong sudo command: $*"
    return 1
}

perform_updates
EOF

    [ "$status" -eq 0 ]
    [[ "$output" == *"Installing all available updates"* ]]
    [[ "$output" == *"Software updates completed"* ]]
}

@test "perform_updates gracefully handles sudo failure for App Store" {
    run bash --noprofile --norc <<'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/manage/update.sh"

APPSTORE_UPDATE_COUNT=1
get_appstore_update_labels() { echo "Xcode"; }

# Simulate user declining sudo or timeout
has_sudo_session() { return 1; }
ensure_sudo_session() { 
    echo "User declined sudo"
    return 1
}

perform_updates
EOF

    [ "$status" -eq 0 ]
    [[ "$output" == *"User declined sudo"* ]]
    [[ "$output" == *"update via System Settings"* ]]
    # Should not crash
}