#!/bin/bash
# SSE Stream Client Library for rdev API
# Provides functions for consuming Server-Sent Events from build streams
#
# Usage:
#   source cookbooks/scripts/lib/stream-client.sh
#   stream_build_with_progress "$API_URL" "$API_KEY" "$PROJECT_ID" "$TASK_ID"

# Colors for output
STREAM_RED='\033[0;31m'
STREAM_GREEN='\033[0;32m'
STREAM_YELLOW='\033[1;33m'
STREAM_BLUE='\033[0;34m'
STREAM_CYAN='\033[0;36m'
STREAM_NC='\033[0m'

# Progress bar width
PROGRESS_BAR_WIDTH=40

# Draw a progress bar
# Arguments: percentage (0-100)
draw_progress_bar() {
    local percent="${1:-0}"
    local filled=$((percent * PROGRESS_BAR_WIDTH / 100))
    local empty=$((PROGRESS_BAR_WIDTH - filled))

    printf "\r["
    printf '%*s' "$filled" '' | tr ' ' '='
    if [[ $filled -lt $PROGRESS_BAR_WIDTH ]]; then
        printf ">"
        printf '%*s' "$((empty - 1))" '' | tr ' ' ' '
    fi
    printf "] %3d%%" "$percent"
}

# Parse SSE data line and extract JSON
# Arguments: data line (after "data: " prefix)
parse_sse_data() {
    local data="$1"
    echo "$data"
}

# Stream build events with progress bar
# Arguments: api_url, api_key, project_id, task_id
# Options:
#   --verbose    Show all output (not just progress)
#   --last-id    Last-Event-ID for reconnection
stream_build_with_progress() {
    local api_url="$1"
    local api_key="$2"
    local project_id="$3"
    local task_id="$4"
    shift 4

    local verbose=false
    local last_event_id=""

    # Parse options
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --verbose)
                verbose=true
                shift
                ;;
            --last-id)
                last_event_id="$2"
                shift 2
                ;;
            *)
                shift
                ;;
        esac
    done

    local stream_url="${api_url}/projects/${project_id}/events?stream_id=${task_id}"
    local curl_args=(
        -s -N
        -H "X-API-Key: ${api_key}"
        -H "Accept: text/event-stream"
    )

    if [[ -n "$last_event_id" ]]; then
        curl_args+=(-H "Last-Event-ID: ${last_event_id}")
    fi

    echo -e "${STREAM_CYAN}Streaming build events...${STREAM_NC}"
    echo ""

    # Track state
    local current_phase="starting"
    local current_percent=0
    local last_event_id_received=""

    # Stream events
    curl "${curl_args[@]}" "$stream_url" 2>/dev/null | while IFS= read -r line; do
        # Skip empty lines
        [[ -z "$line" ]] && continue

        # Parse event ID
        if [[ "$line" == "id:"* ]]; then
            last_event_id_received="${line#id: }"
            continue
        fi

        # Skip event type lines (we parse data directly)
        [[ "$line" == "event:"* ]] && continue

        # Parse data lines
        if [[ "$line" == "data:"* ]]; then
            local data="${line#data: }"
            local event_type
            event_type=$(echo "$data" | jq -r '.type // ""' 2>/dev/null)

            case "$event_type" in
                build.started)
                    echo -e "${STREAM_GREEN}[BUILD STARTED]${STREAM_NC}"
                    current_phase="starting"
                    current_percent=0
                    draw_progress_bar 0
                    ;;

                build.progress)
                    current_phase=$(echo "$data" | jq -r '.phase // "unknown"' 2>/dev/null)
                    current_percent=$(echo "$data" | jq -r '.percentage // 0' 2>/dev/null | cut -d. -f1)
                    draw_progress_bar "$current_percent"
                    printf " [%s]" "$current_phase"
                    ;;

                build.output)
                    if [[ "$verbose" == "true" ]]; then
                        local content
                        content=$(echo "$data" | jq -r '.content // ""' 2>/dev/null)
                        [[ -n "$content" ]] && printf "\n%s" "$content"
                    fi
                    ;;

                build.tool_use)
                    local tool_name
                    tool_name=$(echo "$data" | jq -r '.tool_name // "unknown"' 2>/dev/null)
                    if [[ "$verbose" == "true" ]]; then
                        printf "\n${STREAM_YELLOW}[TOOL: %s]${STREAM_NC}" "$tool_name"
                    fi
                    ;;

                build.error)
                    local error_content
                    error_content=$(echo "$data" | jq -r '.content // ""' 2>/dev/null)
                    printf "\n${STREAM_RED}[ERROR] %s${STREAM_NC}" "$error_content"
                    ;;

                build.completed)
                    echo ""
                    draw_progress_bar 100
                    printf " [complete]"
                    echo ""
                    echo -e "${STREAM_GREEN}[BUILD COMPLETED]${STREAM_NC}"
                    local duration_ms
                    duration_ms=$(echo "$data" | jq -r '.duration_ms // 0' 2>/dev/null)
                    local duration_s=$((duration_ms / 1000))
                    echo "Duration: ${duration_s}s"
                    return 0
                    ;;

                build.failed)
                    echo ""
                    local error
                    error=$(echo "$data" | jq -r '.error // "unknown error"' 2>/dev/null)
                    echo -e "${STREAM_RED}[BUILD FAILED]${STREAM_NC}"
                    echo "Error: $error"
                    return 1
                    ;;

                connected)
                    local reconnecting
                    reconnecting=$(echo "$data" | jq -r '.reconnecting // false' 2>/dev/null)
                    if [[ "$reconnecting" == "true" ]]; then
                        echo -e "${STREAM_YELLOW}[RECONNECTED]${STREAM_NC}"
                    fi
                    ;;

                heartbeat)
                    # Silent heartbeat - just proves connection is alive
                    ;;
            esac
        fi
    done

    # If we get here, the stream closed unexpectedly
    echo ""
    echo -e "${STREAM_YELLOW}[STREAM CLOSED]${STREAM_NC}"
    echo "Last event ID: $last_event_id_received"
    echo "To reconnect: stream_build_with_progress ... --last-id \"$last_event_id_received\""
    return 2
}

# Simple stream consumer that just prints events
# Arguments: api_url, api_key, project_id, task_id
stream_build_simple() {
    local api_url="$1"
    local api_key="$2"
    local project_id="$3"
    local task_id="$4"

    local stream_url="${api_url}/projects/${project_id}/events?stream_id=${task_id}"

    curl -s -N \
        -H "X-API-Key: ${api_key}" \
        -H "Accept: text/event-stream" \
        "$stream_url" 2>/dev/null | while IFS= read -r line; do

        [[ -z "$line" ]] && continue

        if [[ "$line" == "data:"* ]]; then
            local data="${line#data: }"
            local event_type content
            event_type=$(echo "$data" | jq -r '.type // ""' 2>/dev/null)

            case "$event_type" in
                build.output|build.error)
                    content=$(echo "$data" | jq -r '.content // ""' 2>/dev/null)
                    [[ -n "$content" ]] && echo "$content"
                    ;;
                build.completed)
                    echo "[BUILD COMPLETED]"
                    return 0
                    ;;
                build.failed)
                    local error
                    error=$(echo "$data" | jq -r '.error // ""' 2>/dev/null)
                    echo "[BUILD FAILED] $error"
                    return 1
                    ;;
            esac
        fi
    done
}

# Wait for build completion with polling fallback
# Arguments: api_url, api_key, task_id, timeout_seconds
# Returns: 0 on success, 1 on failure, 2 on timeout
wait_for_build_completion() {
    local api_url="$1"
    local api_key="$2"
    local task_id="$3"
    local timeout="${4:-600}"

    local start_time=$(date +%s)

    while true; do
        local elapsed=$(($(date +%s) - start_time))
        if [[ $elapsed -ge $timeout ]]; then
            return 2  # Timeout
        fi

        local response
        response=$(curl -s -X GET "${api_url}/builds/${task_id}" \
            -H "X-API-Key: ${api_key}" 2>/dev/null)

        local status
        status=$(echo "$response" | jq -r '.data.status // "unknown"' 2>/dev/null)

        case "$status" in
            completed)
                local success
                success=$(echo "$response" | jq -r '.data.result.success // false' 2>/dev/null)
                if [[ "$success" == "true" ]]; then
                    return 0
                else
                    return 1
                fi
                ;;
            failed)
                return 1
                ;;
            running|pending)
                sleep 5
                ;;
            *)
                sleep 5
                ;;
        esac
    done
}
