#!/bin/bash
set -euo pipefail

# fetch-ci-data - Fetch GitHub Actions CI failures for a PR or branch
#
# Usage:
#   fetch-ci-data [PR_NUMBER|BRANCH]
#   fetch-ci-data --workflow WORKFLOW_NAME [PR_NUMBER|BRANCH]
#
# Examples:
#   fetch-ci-data 33                    # Fetch CI failures for PR #33
#   fetch-ci-data my-branch             # Fetch CI failures for branch
#   fetch-ci-data                       # Fetch CI failures for current branch
#   fetch-ci-data --workflow ci-cd 33   # Filter to specific workflow
#
# Features:
#   - Automatic error classification (recognized vs unrecognized)
#   - Intelligent research query generation for unrecognized errors
#   - Parallel web search preparation (for Claude Code WebSearch)
#   - Context extraction (Python, JavaScript, Django, FastAPI, etc.)
#
# Output: JSON to stdout, status messages to stderr
# Cache: 5-minute TTL in {REPO}/tmp/.ci-failures-cache/

# Colors for output (to stderr)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# Repository root (for tmp files)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
mkdir -p "$REPO_ROOT/tmp"

# Cache configuration - use repo-local tmp per SKILL.md convention
CACHE_DIR="${REPO_ROOT}/tmp/.ci-failures-cache"
CACHE_TTL=300  # 5 minutes

# Global variables
REPO_OWNER=""
REPO_NAME=""
CURRENT_BRANCH=""
PR_NUMBER=""
WORKFLOW_FILTER=""
CHECK_RUNS_TRUNCATED=false

usage() {
    cat >&2 << EOF
Usage: fetch-ci-data [OPTIONS] [PR_NUMBER|BRANCH]

Fetch GitHub Actions CI failures for a pull request or branch.

OPTIONS:
    --workflow WORKFLOW_NAME    Filter to specific workflow (e.g., 'ci-cd', 'enhanced-ci')
    --no-cache                  Bypass cache and fetch fresh data
    --help                      Show this help message

ARGUMENTS:
    PR_NUMBER                   Pull request number (e.g., 33)
    BRANCH                      Branch name (e.g., 'my-feature-branch')
    (none)                      Use current branch

EXAMPLES:
    fetch-ci-data 33                    # Fetch CI failures for PR #33
    fetch-ci-data my-branch             # Fetch CI failures for branch
    fetch-ci-data                       # Fetch CI failures for current branch
    fetch-ci-data --workflow ci-cd 33   # Filter to specific workflow

FEATURES:
    - Automatic error classification (recognized vs unrecognized)
    - Intelligent research query generation for unrecognized errors
    - Context extraction (Python, JavaScript, Django, FastAPI, etc.)
    - Prepared web search queries for Claude Code WebSearch tool
    - Counts researched errors in summary output

OUTPUT:
    JSON data to stdout (for consumption by other tools)
    Status messages to stderr (for user feedback)

    Output structure includes:
    - summary.researched: Count of errors with research data
    - failures[].research: Research object with search queries and suggestions
      - research.search_queries: Array of prepared search queries
      - research.suggestions: Array of actionable suggestions
      - research.context: Extracted technology context
      - research.auto_research_hint: Hint for Claude Code automation

CACHE:
    Cache location: $CACHE_DIR
    Cache TTL: 5 minutes
    Use --no-cache to bypass cache

EXIT CODES:
    0 - Success
    1 - Error (dependency missing, API failure, etc.)
    2 - No CI failures found
EOF
}

print_status() {
    echo -e "${BLUE}[*]${NC} $*" >&2
}

print_success() {
    echo -e "${GREEN}[✓]${NC} $*" >&2
}

print_error() {
    echo -e "${RED}[✗]${NC} $*" >&2
}

print_warning() {
    echo -e "${YELLOW}[!]${NC} $*" >&2
}

check_dependencies() {
    local missing=()

    if ! command -v gh &> /dev/null; then
        missing+=("gh (GitHub CLI)")
    fi

    if ! command -v jq &> /dev/null; then
        missing+=("jq (JSON processor)")
    fi

    if [ ${#missing[@]} -gt 0 ]; then
        print_error "Missing required dependencies:"
        for dep in "${missing[@]}"; do
            echo "  - $dep" >&2
        done
        echo >&2
        echo "Install with:" >&2
        echo "  brew install gh jq" >&2
        exit 1
    fi
}

get_repo_info() {
    print_status "Detecting repository..."

    # Get repository info from git remote
    local remote_url
    remote_url=$(git config --get remote.origin.url 2>/dev/null || echo "")

    if [ -z "$remote_url" ]; then
        print_error "Not in a git repository"
        exit 1
    fi

    # Parse owner/repo from URL
    # Supports: git@github.com:owner/repo.git and https://github.com/owner/repo.git
    if [[ $remote_url =~ github\.com[:/]([^/]+)/([^/\.]+) ]]; then
        REPO_OWNER="${BASH_REMATCH[1]}"
        REPO_NAME="${BASH_REMATCH[2]}"
    else
        print_error "Could not parse GitHub repository from remote URL: $remote_url"
        exit 1
    fi

    print_success "Repository: $REPO_OWNER/$REPO_NAME"
}

get_current_branch() {
    CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")

    if [ -z "$CURRENT_BRANCH" ]; then
        print_error "Could not determine current branch"
        exit 1
    fi

    print_status "Current branch: $CURRENT_BRANCH"
}

get_pr_for_branch() {
    local branch="${1:-$CURRENT_BRANCH}"

    print_status "Finding PR for branch: $branch"

    # Try to find PR number from gh CLI
    local pr_number
    pr_number=$(gh pr list --head "$branch" --json number --jq '.[0].number' 2>/dev/null || echo "")

    if [ -n "$pr_number" ]; then
        print_success "Found PR #$pr_number"
        echo "$pr_number"
        return 0
    else
        print_warning "No PR found for branch: $branch"
        return 1
    fi
}

get_cache_key() {
    local identifier="$1"
    local workflow="${2:-all}"
    echo "${REPO_OWNER}_${REPO_NAME}_${identifier}_${workflow}"
}

get_cached_data() {
    local cache_key="$1"
    local cache_file="$CACHE_DIR/$cache_key.json"

    if [ ! -f "$cache_file" ]; then
        return 1
    fi

    # Check if cache is still valid
    local cache_age
    cache_age=$(($(date +%s) - $(stat -f %m "$cache_file" 2>/dev/null || stat -c %Y "$cache_file" 2>/dev/null || echo 0)))

    if [ "$cache_age" -gt "$CACHE_TTL" ]; then
        print_status "Cache expired (age: ${cache_age}s, TTL: ${CACHE_TTL}s)"
        return 1
    fi

    print_success "Using cached data (age: ${cache_age}s)"
    cat "$cache_file"
    return 0
}

save_cached_data() {
    local cache_key="$1"
    local data="$2"

    mkdir -p "$CACHE_DIR"
    local cache_file="$CACHE_DIR/$cache_key.json"

    echo "$data" > "$cache_file"
    print_status "Cached data saved to: $cache_file"
}

fetch_failures_for_pr() {
    local pr_number="$1"

    # Get the PR's head commit SHA — this is the commit CI actually ran against
    print_status "Fetching head SHA for PR #$pr_number..."
    local head_sha
    head_sha=$(gh pr view "$pr_number" --repo "$REPO_OWNER/$REPO_NAME" --json headRefOid --jq '.headRefOid' 2>/dev/null)

    if [ -z "$head_sha" ]; then
        print_error "Could not get head SHA for PR #$pr_number"
        echo "[]"
        return 1
    fi

    print_status "Head SHA: ${head_sha:0:12}"

    # Query check-runs for this commit (catches ALL CI regardless of trigger event)
    # This is what 'gh pr checks' uses under the hood
    # NOTE: per_page=100 is the GitHub API maximum. PRs with >100 check runs
    # (rare, mainly monorepos with large matrix jobs) will have later checks
    # silently omitted. Pagination not implemented as it adds complexity for
    # a scenario that practically never occurs in this codebase.
    print_status "Fetching check runs for commit..."
    local api_response
    api_response=$(gh api "repos/$REPO_OWNER/$REPO_NAME/commits/$head_sha/check-runs?per_page=100" 2>/dev/null || echo '{"total_count":0,"check_runs":[]}')

    local total_api_count
    total_api_count=$(echo "$api_response" | jq '.total_count // 0')

    local failed_checks
    # NOTE: Only captures GitHub Actions check runs (.app.slug == "github-actions").
    # Third-party CI systems (CircleCI, Jenkins, etc.) that register check runs
    # with a different app slug are excluded. Users should verify in the GitHub
    # Actions UI if they suspect third-party CI failures.
    failed_checks=$(echo "$api_response" | jq '[.check_runs[] | select(.conclusion == "failure" and (.app.slug // "") == "github-actions")]')

    local check_count
    check_count=$(echo "$failed_checks" | jq 'length')

    if [ "$total_api_count" -gt 100 ]; then
        print_warning "API returned $total_api_count total check runs (per_page=100) — some failed checks may be missing"
        CHECK_RUNS_TRUNCATED=true
        # Downstream consumers: check_runs_truncated=true in the JSON output
        # means the failure list may be incomplete. The ci-failures SKILL.md
        # should surface this flag to the user and suggest manual verification
        # via the GitHub Actions UI when set.
    fi

    if [ "$check_count" -eq 0 ]; then
        print_success "No failed checks found"
        echo "[]"
        return 0
    fi

    print_status "Found $check_count failed check(s), fetching job details..."

    local all_failures="[]"

    while IFS= read -r check; do
        local job_id job_name job_url
        job_id=$(echo "$check" | jq -r '.id')
        job_name=$(echo "$check" | jq -r '.name')
        job_url=$(echo "$check" | jq -r '.html_url')

        print_status "  Processing: $job_name"

        # Fetch full job details (includes steps and workflow name)
        local job_details
        job_details=$(gh api "repos/$REPO_OWNER/$REPO_NAME/actions/jobs/$job_id" 2>/dev/null || echo "{}")

        local workflow_name run_id run_url
        workflow_name=$(echo "$job_details" | jq -r '.workflow_name // "Unknown"')
        run_id=$(echo "$job_details" | jq -r '.run_id // 0')
        if [ "$run_id" = "0" ] || [ "$run_id" = "null" ]; then
            # Job details unavailable — use the check run's own URL instead
            run_url="$job_url"
        else
            run_url="https://github.com/$REPO_OWNER/$REPO_NAME/actions/runs/$run_id"
        fi

        # Apply workflow filter if set
        if [ -n "$WORKFLOW_FILTER" ]; then
            if ! echo "$workflow_name" | grep -qFi "$WORKFLOW_FILTER"; then
                print_status "    Skipped (workflow filter: $WORKFLOW_FILTER)"
                continue
            fi
        fi

        # Get failed steps from job details
        local failed_steps
        failed_steps=$(echo "$job_details" | jq -c '[.steps[]? | select(.conclusion == "failure")]')
        local step_count
        step_count=$(echo "$failed_steps" | jq 'length')

        if [ "$step_count" -eq 0 ]; then
            # Job failed but no specific step failed — create generic entry
            local severity
            severity=$(classify_failure_severity "$job_name" "" "failure")

            local research=""
            if ! is_error_recognized "$job_name" "Unknown"; then
                print_status "    Unrecognized error, preparing research queries..."
                research=$(research_error "$job_name" "Unknown" "$workflow_name" "$job_url")
            fi

            local failure
            if [ -n "$research" ]; then
                failure=$(jq -n \
                    --arg workflow "$workflow_name" \
                    --arg workflow_id "$run_id" \
                    --arg workflow_url "$run_url" \
                    --arg job "$job_name" \
                    --arg job_id "$job_id" \
                    --arg job_url "$job_url" \
                    --arg step "Unknown" \
                    --arg conclusion "failure" \
                    --arg severity "$severity" \
                    --argjson research "$research" \
                    '{workflow: $workflow, workflow_id: $workflow_id, workflow_url: $workflow_url, job: $job, job_id: $job_id, job_url: $job_url, step: $step, conclusion: $conclusion, severity: $severity, research: $research}')
            else
                failure=$(jq -n \
                    --arg workflow "$workflow_name" \
                    --arg workflow_id "$run_id" \
                    --arg workflow_url "$run_url" \
                    --arg job "$job_name" \
                    --arg job_id "$job_id" \
                    --arg job_url "$job_url" \
                    --arg step "Unknown" \
                    --arg conclusion "failure" \
                    --arg severity "$severity" \
                    '{workflow: $workflow, workflow_id: $workflow_id, workflow_url: $workflow_url, job: $job, job_id: $job_id, job_url: $job_url, step: $step, conclusion: $conclusion, severity: $severity}')
            fi
            all_failures=$(echo "$all_failures" | jq --argjson failure "$failure" '. + [$failure]')
        else
            while IFS= read -r step; do
                local step_name step_number
                step_name=$(echo "$step" | jq -r '.name')
                step_number=$(echo "$step" | jq -r '.number')

                print_status "    Failed step: $step_name"

                local severity
                severity=$(classify_failure_severity "$job_name" "$step_name" "failure")

                local research=""
                if ! is_error_recognized "$job_name" "$step_name"; then
                    print_status "      Unrecognized error, preparing research queries..."
                    research=$(research_error "$job_name" "$step_name" "$workflow_name" "$job_url")
                fi

                local failure
                if [ -n "$research" ]; then
                    failure=$(jq -n \
                        --arg workflow "$workflow_name" \
                        --arg workflow_id "$run_id" \
                        --arg workflow_url "$run_url" \
                        --arg job "$job_name" \
                        --arg job_id "$job_id" \
                        --arg job_url "$job_url" \
                        --arg step "$step_name" \
                        --arg step_number "$step_number" \
                        --arg conclusion "failure" \
                        --arg severity "$severity" \
                        --argjson research "$research" \
                        '{workflow: $workflow, workflow_id: $workflow_id, workflow_url: $workflow_url, job: $job, job_id: $job_id, job_url: $job_url, step: $step, step_number: ($step_number | tonumber), conclusion: $conclusion, severity: $severity, research: $research}')
                else
                    failure=$(jq -n \
                        --arg workflow "$workflow_name" \
                        --arg workflow_id "$run_id" \
                        --arg workflow_url "$run_url" \
                        --arg job "$job_name" \
                        --arg job_id "$job_id" \
                        --arg job_url "$job_url" \
                        --arg step "$step_name" \
                        --arg step_number "$step_number" \
                        --arg conclusion "failure" \
                        --arg severity "$severity" \
                        '{workflow: $workflow, workflow_id: $workflow_id, workflow_url: $workflow_url, job: $job, job_id: $job_id, job_url: $job_url, step: $step, step_number: ($step_number | tonumber), conclusion: $conclusion, severity: $severity}')
                fi
                all_failures=$(echo "$all_failures" | jq --argjson failure "$failure" '. + [$failure]')
            done < <(echo "$failed_steps" | jq -c '.[]')
        fi
    done < <(echo "$failed_checks" | jq -c '.[]')

    echo "$all_failures"
}

classify_failure_severity() {
    local job_name="$1"
    local step_name="$2"
    local conclusion="$3"

    # Critical: Build failures, deployment failures, test suite crashes
    if [[ "$job_name" =~ [Bb]uild ]] || [[ "$job_name" =~ [Dd]eploy ]]; then
        echo "critical"
        return
    fi

    if [[ "$step_name" =~ [Bb]uild ]] || [[ "$step_name" =~ [Dd]eploy ]]; then
        echo "critical"
        return
    fi

    # Major: Test failures, linting errors, type checking
    if [[ "$job_name" =~ [Tt]est ]] || [[ "$job_name" =~ [Ll]int ]] || [[ "$job_name" =~ [Tt]ype ]]; then
        echo "major"
        return
    fi

    if [[ "$step_name" =~ [Tt]est ]] || [[ "$step_name" =~ [Ll]int ]] || [[ "$step_name" =~ [Tt]ype ]]; then
        echo "major"
        return
    fi

    if [[ "$step_name" =~ pytest ]] || [[ "$step_name" =~ mypy ]] || [[ "$step_name" =~ ruff ]]; then
        echo "major"
        return
    fi

    # Minor: Everything else
    echo "minor"
}

is_error_recognized() {
    local job_name="$1"
    local step_name="$2"

    # Known error patterns (return 0 if recognized)

    # Recognized: pytest/test failures
    if [[ "$job_name" =~ [Tt]est ]] || [[ "$step_name" =~ [Tt]est ]]; then
        return 0
    fi

    if [[ "$step_name" =~ pytest ]] || [[ "$step_name" =~ unittest ]]; then
        return 0
    fi

    # Recognized: type checking errors
    if [[ "$step_name" =~ mypy ]] || [[ "$step_name" =~ type.*check ]]; then
        return 0
    fi

    # Recognized: linting errors
    if [[ "$step_name" =~ ruff ]] || [[ "$step_name" =~ [Ll]int ]] || [[ "$step_name" =~ flake8 ]] || [[ "$step_name" =~ pylint ]]; then
        return 0
    fi

    # Recognized: Docker errors
    if [[ "$step_name" =~ [Dd]ocker ]] || [[ "$step_name" =~ container ]]; then
        return 0
    fi

    # Recognized: package manager errors
    if [[ "$step_name" =~ npm ]] || [[ "$step_name" =~ yarn ]] || [[ "$step_name" =~ pip ]] || [[ "$step_name" =~ poetry ]]; then
        return 0
    fi

    # Recognized: standard CI steps
    if [[ "$step_name" =~ [Ss]etup ]] || [[ "$step_name" =~ [Cc]heckout ]] || [[ "$step_name" =~ [Cc]ache ]]; then
        return 0
    fi

    # Unrecognized error
    return 1
}

extract_error_context() {
    local job_name="$1"
    local step_name="$2"

    # Extract technology/tool from job or step name
    local context=""

    # Programming languages
    if [[ "$job_name $step_name" =~ [Pp]ython ]]; then
        context="${context}Python "
    elif [[ "$job_name $step_name" =~ [Jj]ava[Ss]cript ]]; then
        context="${context}JavaScript "
    elif [[ "$job_name $step_name" =~ [Tt]ype[Ss]cript ]]; then
        context="${context}TypeScript "
    fi

    # Frameworks
    if [[ "$job_name $step_name" =~ [Dd]jango ]]; then
        context="${context}Django "
    elif [[ "$job_name $step_name" =~ [Ff]lask ]]; then
        context="${context}Flask "
    elif [[ "$job_name $step_name" =~ [Ff]ast[Aa][Pp][Ii] ]]; then
        context="${context}FastAPI "
    fi

    # CI/CD platforms
    if [[ "$job_name $step_name" =~ [Gg]itHub.*[Aa]ctions ]]; then
        context="${context}GitHub-Actions "
    fi

    echo "$context" | sed 's/ $//'
}

research_error() {
    local job_name="$1"
    local step_name="$2"
    local workflow_name="$3"
    local job_url="$4"

    # Extract context for better search queries
    local context
    context=$(extract_error_context "$job_name" "$step_name")

    # Generate targeted search queries
    local queries=()

    # Query 1: Direct error with context
    local query1="${context} ${step_name} CI failure solution"
    queries+=("$query1")

    # Query 2: GitHub issues search
    local query2="GitHub issues ${job_name} ${step_name} failure"
    queries+=("$query2")

    # Query 3: Stack Overflow search
    local query3="Stack Overflow ${context} ${step_name} error"
    queries+=("$query3")

    # Query 4: Recent breaking changes (current year)
    local current_year
    current_year=$(date +%Y)
    local query4="${context} breaking changes ${current_year} CI"
    queries+=("$query4")

    # Query 5: GitHub Actions specific (if applicable)
    if [[ "$workflow_name" =~ [Gg]itHub ]]; then
        local query5="GitHub Actions ${step_name} failure troubleshooting"
        queries+=("$query5")
    fi

    # Generate suggestions
    local suggestions=()
    suggestions+=("Search GitHub Issues for similar '${step_name}' failures")
    suggestions+=("Check Stack Overflow for '${context} ${step_name}' solutions")
    suggestions+=("Review recent dependency updates that might cause '${step_name}' issues")
    suggestions+=("Examine full error logs at: ${job_url}")
    suggestions+=("Look for breaking changes in ${context} ecosystem (${current_year})")

    # Create JSON array of queries
    local queries_json
    queries_json=$(printf '%s\n' "${queries[@]}" | jq -R . | jq -s .)

    # Create JSON array of suggestions
    local suggestions_json
    suggestions_json=$(printf '%s\n' "${suggestions[@]}" | jq -R . | jq -s .)

    # Build research object
    jq -n \
        --arg job "$job_name" \
        --arg step "$step_name" \
        --arg workflow "$workflow_name" \
        --arg context "$context" \
        --argjson queries "$queries_json" \
        --argjson suggestions "$suggestions_json" \
        '{
            job: $job,
            step: $step,
            workflow: $workflow,
            context: $context,
            research_needed: true,
            search_queries: $queries,
            suggestions: $suggestions,
            auto_research_hint: "Claude Code can automatically execute these searches using WebSearch tool"
        }'
}

generate_output() {
    local pr_number="$1"
    local failures="$2"

    local critical_count
    critical_count=$(echo "$failures" | jq '[.[] | select(.severity == "critical")] | length')
    local major_count
    major_count=$(echo "$failures" | jq '[.[] | select(.severity == "major")] | length')
    local minor_count
    minor_count=$(echo "$failures" | jq '[.[] | select(.severity == "minor")] | length')
    local total_count
    total_count=$(echo "$failures" | jq 'length')
    local researched_count
    researched_count=$(echo "$failures" | jq '[.[] | select(.research != null)] | length')

    if [ "$researched_count" -gt 0 ]; then
        print_status "Summary: $total_count failures (Critical: $critical_count, Major: $major_count, Minor: $minor_count, Researched: $researched_count)"
    else
        print_status "Summary: $total_count failures (Critical: $critical_count, Major: $major_count, Minor: $minor_count)"
    fi

    # Generate final JSON output
    jq -n \
        --arg repo "$REPO_OWNER/$REPO_NAME" \
        --arg pr "$pr_number" \
        --argjson failures "$failures" \
        --arg critical "$critical_count" \
        --arg major "$major_count" \
        --arg minor "$minor_count" \
        --arg total "$total_count" \
        --arg researched "$researched_count" \
        --argjson truncated "$CHECK_RUNS_TRUNCATED" \
        --arg fetched_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
        '{
            repository: $repo,
            pr_number: ($pr | tonumber),
            summary: {
                total: ($total | tonumber),
                critical: ($critical | tonumber),
                major: ($major | tonumber),
                minor: ($minor | tonumber),
                researched: ($researched | tonumber)
            },
            check_runs_truncated: $truncated,
            failures: $failures,
            fetched_at: $fetched_at
        }'
}

main() {
    local use_cache=true
    local target=""

    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            --workflow)
                WORKFLOW_FILTER="$2"
                shift 2
                ;;
            --no-cache)
                use_cache=false
                shift
                ;;
            --help|-h)
                usage
                exit 0
                ;;
            -*)
                print_error "Unknown option: $1"
                usage
                exit 1
                ;;
            *)
                target="$1"
                shift
                ;;
        esac
    done

    # Check dependencies
    check_dependencies

    # Get repository info
    get_repo_info

    # Determine target (PR number or branch)
    if [ -z "$target" ]; then
        # Use current branch
        get_current_branch
        target="$CURRENT_BRANCH"
    fi

    # Check if target is a PR number
    if [[ "$target" =~ ^[0-9]+$ ]]; then
        PR_NUMBER="$target"
    else
        # Target is a branch name, find PR
        if ! PR_NUMBER=$(get_pr_for_branch "$target"); then
            print_error "Could not find PR for branch: $target"
            exit 1
        fi
    fi

    print_status "Fetching CI failures for PR #$PR_NUMBER"

    # Check cache
    local cache_key
    cache_key=$(get_cache_key "pr_${PR_NUMBER}" "${WORKFLOW_FILTER:-all}")

    if [ "$use_cache" = true ]; then
        if cached_data=$(get_cached_data "$cache_key"); then
            echo "$cached_data"
            exit 0
        fi
    fi

    # Fetch failures via check-runs API (comprehensive — catches all trigger events)
    local failures
    failures=$(fetch_failures_for_pr "$PR_NUMBER")

    if [ "$failures" = "[]" ] || [ -z "$failures" ]; then
        print_success "No CI failures found!"
        local empty_output
        empty_output=$(generate_output "$PR_NUMBER" "[]")
        echo "$empty_output"
        exit 2
    fi

    # Generate output
    local output
    output=$(generate_output "$PR_NUMBER" "$failures")

    # Save to cache
    if [ "$use_cache" = true ]; then
        save_cached_data "$cache_key" "$output"
    fi

    # Output to stdout
    echo "$output"

    print_success "CI failure data fetched successfully"
}

main "$@"
