#!/opt/local/bin/bash
# Sudo Session Manager
# Unified sudo authentication and keepalive management

set -euo pipefail

# ============================================================================
# Touch ID and Clamshell Detection
# ============================================================================

check_touchid_support() {
    # Check sudo_local first (Sonoma+)
    if [[ -f /etc/pam.d/sudo_local ]]; then
        grep -q "pam_tid.so" /etc/pam.d/sudo_local 2> /dev/null
        return $?
    fi

    # Fallback to checking sudo directly
    if [[ -f /etc/pam.d/sudo ]]; then
        grep -q "pam_tid.so" /etc/pam.d/sudo 2> /dev/null
        return $?
    fi
    return 1
}

# Detect clamshell mode (lid closed)
is_clamshell_mode() {
    # ioreg is missing (not macOS) -> treat as lid open
    if ! command -v ioreg > /dev/null 2>&1; then
        return 1
    fi

    # Check if lid is closed; ignore pipeline failures so set -e doesn't exit
    local clamshell_state=""
    clamshell_state=$( (ioreg -r -k AppleClamshellState -d 4 2> /dev/null |
        grep "AppleClamshellState" |
        head -1) || true)

    if [[ "$clamshell_state" =~ \"AppleClamshellState\"\ =\ Yes ]]; then
        return 0 # Lid is closed
    fi
    return 1 # Lid is open
}

_request_password() {
    local tty_path="$1"
    local attempts=0
    local show_hint=true

    # Extra safety: ensure sudo cache is cleared before password input
    sudo -k 2> /dev/null

    # Save original terminal settings and ensure they're restored on exit
    local stty_orig
    stty_orig=$(stty -g < "$tty_path" 2> /dev/null || echo "")
    trap '[[ -n "${stty_orig:-}" ]] && stty "${stty_orig:-}" < "$tty_path" 2> /dev/null || true' RETURN

    while ((attempts < 3)); do
        local password=""

        # Show hint on first attempt about Touch ID appearing again
        if [[ $show_hint == true ]] && check_touchid_support; then
            echo -e "${GRAY}Note: Touch ID dialog may appear once more, just cancel it${NC}" > "$tty_path"
            show_hint=false
        fi

        printf "${PURPLE}${ICON_ARROW}${NC} Password: " > "$tty_path"

        # Disable terminal echo to hide password input (keep canonical mode for reliable input)
        stty -echo < "$tty_path" 2> /dev/null || true
        IFS= read -r password < "$tty_path" || password=""
        # Restore terminal echo immediately
        stty echo < "$tty_path" 2> /dev/null || true

        printf "\n" > "$tty_path"

        if [[ -z "$password" ]]; then
            unset password
            ((attempts++))
            if [[ $attempts -lt 3 ]]; then
                echo -e "${GRAY}${ICON_WARNING}${NC} Password cannot be empty" > "$tty_path"
            fi
            continue
        fi

        # Verify password with sudo
        # NOTE: macOS PAM will trigger Touch ID before password auth - this is system behavior
        if printf '%s\n' "$password" | sudo -S -p "" -v > /dev/null 2>&1; then
            unset password
            return 0
        fi

        unset password
        ((attempts++))
        if [[ $attempts -lt 3 ]]; then
            echo -e "${GRAY}${ICON_WARNING}${NC} Incorrect password, try again" > "$tty_path"
        fi
    done

    return 1
}

request_sudo_access() {
    local prompt_msg="${1:-Admin access required}"

    # Check if already have sudo access
    if sudo -n true 2> /dev/null; then
        return 0
    fi

    # Get TTY path
    local tty_path="/dev/tty"
    if [[ ! -r "$tty_path" || ! -w "$tty_path" ]]; then
        tty_path=$(tty 2> /dev/null || echo "")
        if [[ -z "$tty_path" || ! -r "$tty_path" || ! -w "$tty_path" ]]; then
            log_error "No interactive terminal available"
            return 1
        fi
    fi

    sudo -k

    # Check if in clamshell mode - if yes, skip Touch ID entirely
    if is_clamshell_mode; then
        echo -e "${PURPLE}${ICON_ARROW}${NC} ${prompt_msg}"
        if _request_password "$tty_path"; then
            # Clear all prompt lines (use safe clearing method)
            safe_clear_lines 3 "$tty_path"
            return 0
        fi
        return 1
    fi

    # Not in clamshell mode - try Touch ID if configured
    if ! check_touchid_support; then
        echo -e "${PURPLE}${ICON_ARROW}${NC} ${prompt_msg}"
        if _request_password "$tty_path"; then
            # Clear all prompt lines (use safe clearing method)
            safe_clear_lines 3 "$tty_path"
            return 0
        fi
        return 1
    fi

    # Touch ID is available and not in clamshell mode
    echo -e "${PURPLE}${ICON_ARROW}${NC} ${prompt_msg} ${GRAY}, Touch ID or password${NC}"

    # Start sudo in background so we can monitor and control it
    sudo -v < /dev/null > /dev/null 2>&1 &
    local sudo_pid=$!

    # Wait for sudo to complete or timeout (5 seconds)
    local elapsed=0
    local timeout=50 # 50 * 0.1s = 5 seconds
    while ((elapsed < timeout)); do
        if ! kill -0 "$sudo_pid" 2> /dev/null; then
            # Process exited
            wait "$sudo_pid" 2> /dev/null
            local exit_code=$?
            if [[ $exit_code -eq 0 ]] && sudo -n true 2> /dev/null; then
                # Touch ID succeeded - clear the prompt line
                safe_clear_lines 1 "$tty_path"
                return 0
            fi
            # Touch ID failed or cancelled
            break
        fi
        sleep 0.1
        ((elapsed++))
    done

    # Touch ID failed/cancelled - clean up thoroughly before password input

    # Kill the sudo process if still running
    if kill -0 "$sudo_pid" 2> /dev/null; then
        kill -9 "$sudo_pid" 2> /dev/null
        wait "$sudo_pid" 2> /dev/null || true
    fi

    # Clear sudo state immediately
    sudo -k 2> /dev/null

    # IMPORTANT: Wait longer for macOS to fully close Touch ID UI and SecurityAgent
    # Without this delay, subsequent sudo calls may re-trigger Touch ID
    sleep 1

    # Clear any leftover prompts on the screen
    safe_clear_line "$tty_path"

    # Now use our password input (this should not trigger Touch ID again)
    if _request_password "$tty_path"; then
        # Clear all prompt lines (use safe clearing method)
        safe_clear_lines 3 "$tty_path"
        return 0
    fi
    return 1
}

# ============================================================================
# Sudo Session Management
# ============================================================================

# Global state
MOLE_SUDO_KEEPALIVE_PID=""
MOLE_SUDO_ESTABLISHED="false"

# Start sudo keepalive
_start_sudo_keepalive() {
    # Start background keepalive process with all outputs redirected
    # This is critical: command substitution waits for all file descriptors to close
    (
        # Initial delay to let sudo cache stabilize after password entry
        # This prevents immediately triggering Touch ID again
        sleep 2

        local retry_count=0
        while true; do
            if ! sudo -n -v 2> /dev/null; then
                ((retry_count++))
                if [[ $retry_count -ge 3 ]]; then
                    exit 1
                fi
                sleep 5
                continue
            fi
            retry_count=0
            sleep 30
            kill -0 "$$" 2> /dev/null || exit
        done
    ) > /dev/null 2>&1 &

    local pid=$!
    echo $pid
}

# Stop sudo keepalive
_stop_sudo_keepalive() {
    local pid="${1:-}"
    if [[ -n "$pid" ]]; then
        kill "$pid" 2> /dev/null || true
        wait "$pid" 2> /dev/null || true
    fi
}

# Check if sudo session is active
has_sudo_session() {
    sudo -n true 2> /dev/null
}

# Request administrative access
request_sudo() {
    local prompt_msg="${1:-Admin access required}"

    if has_sudo_session; then
        return 0
    fi

    # Use the robust implementation from common.sh
    if request_sudo_access "$prompt_msg"; then
        return 0
    else
        return 1
    fi
}

# Maintain active sudo session with keepalive
ensure_sudo_session() {
    local prompt="${1:-Admin access required}"

    # Check if already established
    if has_sudo_session && [[ "$MOLE_SUDO_ESTABLISHED" == "true" ]]; then
        return 0
    fi

    # Stop old keepalive if exists
    if [[ -n "$MOLE_SUDO_KEEPALIVE_PID" ]]; then
        _stop_sudo_keepalive "$MOLE_SUDO_KEEPALIVE_PID"
        MOLE_SUDO_KEEPALIVE_PID=""
    fi

    # Request sudo access
    if ! request_sudo "$prompt"; then
        MOLE_SUDO_ESTABLISHED="false"
        return 1
    fi

    # Start keepalive
    MOLE_SUDO_KEEPALIVE_PID=$(_start_sudo_keepalive)

    MOLE_SUDO_ESTABLISHED="true"
    return 0
}

# Stop sudo session and cleanup
stop_sudo_session() {
    if [[ -n "$MOLE_SUDO_KEEPALIVE_PID" ]]; then
        _stop_sudo_keepalive "$MOLE_SUDO_KEEPALIVE_PID"
        MOLE_SUDO_KEEPALIVE_PID=""
    fi
    MOLE_SUDO_ESTABLISHED="false"
}

# Register cleanup on script exit
register_sudo_cleanup() {
    trap stop_sudo_session EXIT INT TERM
}

# Predict if operation requires administrative access
will_need_sudo() {
    local -a operations=("$@")
    for op in "${operations[@]}"; do
        case "$op" in
            system_update | appstore_update | macos_update | firewall | touchid | rosetta | system_fix)
                return 0
                ;;
        esac
    done
    return 1
}
