#!/bin/bash
set -euo pipefail

# ============================================================================
# CI Job Details - Deep-Dive Investigation of Specific CI Job Failures
# ============================================================================
# Tier 2 investigation tool for detailed analysis of a specific CI job failure.
# Complements ci-quick-review (Tier 1) by providing complete logs, error traces,
# and contextual information for a single job.
#
# Usage:
#   get-ci-job-details <job_id> [pr_number]
#   get-ci-job-details <job_url> [pr_number]
#
# Examples:
#   get-ci-job-details 56174634733          # By job ID
#   get-ci-job-details 56174634733 33       # With PR context
#   get-ci-job-details https://github.com/user/repo/actions/runs/123/job/456
#
# Output:
#   - Complete job logs
#   - Job metadata (name, steps, conclusion, timing)
#   - Failed step details with error messages
#   - Stack traces (formatted)
#   - Related jobs in same workflow run
#   - GitHub links
#   - Suggested fixes based on error patterns
# ============================================================================

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
BOLD='\033[1m'
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
CACHE_DIR="$REPO_ROOT/tmp/.ci-job-details-cache"
CACHE_TTL=300  # 5 minutes
mkdir -p "$CACHE_DIR"

# Global variables
REPO_OWNER=""
REPO_NAME=""
JOB_ID=""
PR_NUMBER=""

usage() {
    cat << EOF
Usage: $(basename "$0") <JOB_ID|JOB_URL> [PR_NUMBER]

Deep-dive investigation into specific CI job failures.

ARGUMENTS:
    JOB_ID                      GitHub Actions job ID (e.g., 56174634733)
    JOB_URL                     GitHub Actions job URL
    PR_NUMBER                   Optional PR number for additional context

EXAMPLES:
    # By job ID
    $(basename "$0") 56174634733

    # By job URL
    $(basename "$0") https://github.com/user/repo/actions/runs/123/job/456

    # With PR number for context
    $(basename "$0") 56174634733 33

OUTPUT:
    - Complete job logs
    - Failed step error messages and stack traces
    - Job metadata (timing, status, steps)
    - Related jobs in workflow run
    - Suggested fixes based on error patterns
    - GitHub links for further investigation

CACHE:
    Cache location: $CACHE_DIR
    Cache TTL: 5 minutes

EXIT CODES:
    0 - Success
    1 - Error (dependency missing, API failure, invalid job ID)
    2 - Job not found

EOF
    exit 0
}

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
    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"
}

extract_job_id() {
    local input="$1"

    # Check if input is a URL
    if [[ $input =~ https://github\.com/.*/actions/runs/.*/job/([0-9]+) ]]; then
        JOB_ID="${BASH_REMATCH[1]}"
        print_status "Extracted job ID from URL: $JOB_ID"
    elif [[ $input =~ ^[0-9]+$ ]]; then
        JOB_ID="$input"
        print_status "Using job ID: $JOB_ID"
    else
        print_error "Invalid job ID or URL: $input"
        echo "" >&2
        echo "Expected:" >&2
        echo "  - Job ID: 56174634733" >&2
        echo "  - Job URL: https://github.com/user/repo/actions/runs/123/job/456" >&2
        exit 1
    fi
}

get_cache_file() {
    local job_id="$1"
    echo "$CACHE_DIR/job-${job_id}.json"
}

is_cache_valid() {
    local cache_file="$1"

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

    # Check if cache is within TTL
    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" -lt "$CACHE_TTL" ]; then
        return 0
    else
        return 1
    fi
}

fetch_job_details() {
    local job_id="$1"
    local cache_file
    cache_file=$(get_cache_file "$job_id")

    # Check cache first
    if is_cache_valid "$cache_file"; then
        print_success "Using cached job details (age: $(($(date +%s) - $(stat -f %m "$cache_file" 2>/dev/null || stat -c %Y "$cache_file")))s)"
        cat "$cache_file"
        return 0
    fi

    print_status "Fetching job details from GitHub API..."

    # Fetch job details
    local job_data
    if ! job_data=$(gh api "repos/$REPO_OWNER/$REPO_NAME/actions/jobs/$job_id" 2>&1); then
        print_error "Failed to fetch job details: $job_data"
        exit 1
    fi

    # Validate JSON
    if ! echo "$job_data" | jq empty 2>/dev/null; then
        print_error "Invalid JSON response from GitHub API"
        exit 1
    fi

    # Check if job exists
    if echo "$job_data" | jq -e '.message == "Not Found"' &>/dev/null; then
        print_error "Job not found: $job_id"
        exit 2
    fi

    # Cache the result
    echo "$job_data" > "$cache_file"
    print_success "Job details fetched and cached"

    echo "$job_data"
}

fetch_job_logs() {
    local job_id="$1"
    local cache_file="$CACHE_DIR/job-${job_id}-logs.txt"

    # Check cache first
    if is_cache_valid "$cache_file"; then
        print_success "Using cached job logs"
        cat "$cache_file"
        return 0
    fi

    print_status "Fetching job logs from GitHub API..."

    # Fetch job logs (text format)
    local job_logs
    if ! job_logs=$(gh api "repos/$REPO_OWNER/$REPO_NAME/actions/jobs/$job_id/logs" 2>&1); then
        print_warning "Failed to fetch job logs (may require authentication)"
        echo ""
        return 1
    fi

    # Cache the result
    echo "$job_logs" > "$cache_file"
    print_success "Job logs fetched and cached"

    echo "$job_logs"
}

fetch_workflow_run_jobs() {
    local run_id="$1"
    local cache_file="$CACHE_DIR/run-${run_id}-jobs.json"

    # Check cache first
    if is_cache_valid "$cache_file"; then
        cat "$cache_file"
        return 0
    fi

    print_status "Fetching related jobs in workflow run..."

    # Fetch all jobs in the workflow run
    local jobs_data
    if ! jobs_data=$(gh api "repos/$REPO_OWNER/$REPO_NAME/actions/runs/$run_id/jobs" 2>&1); then
        print_warning "Failed to fetch workflow run jobs"
        echo '{"jobs": []}'
        return 1
    fi

    # Cache the result
    echo "$jobs_data" > "$cache_file"

    echo "$jobs_data"
}

format_duration() {
    local start="$1"
    local end="$2"

    # Convert ISO 8601 to epoch seconds
    local start_epoch
    local end_epoch
    start_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$start" +%s 2>/dev/null || date -d "$start" +%s 2>/dev/null || echo 0)
    end_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$end" +%s 2>/dev/null || date -d "$end" +%s 2>/dev/null || echo 0)

    local duration=$((end_epoch - start_epoch))

    if [ "$duration" -lt 60 ]; then
        echo "${duration}s"
    elif [ "$duration" -lt 3600 ]; then
        echo "$((duration / 60))m $((duration % 60))s"
    else
        echo "$((duration / 3600))h $((duration % 3600 / 60))m"
    fi
}

extract_error_patterns() {
    local logs="$1"

    # Extract common error patterns
    local errors=""

    # Python exceptions
    errors+=$(echo "$logs" | grep -E "^(Traceback|[A-Za-z]+Error:|FAILED)" || true)
    errors+=$'\n'

    # TypeScript/JavaScript errors
    errors+=$(echo "$logs" | grep -E "^(error TS[0-9]+:|Error:|    at )" || true)
    errors+=$'\n'

    # Build errors
    errors+=$(echo "$logs" | grep -E "^(ERROR:|FAILED:|fatal:)" || true)
    errors+=$'\n'

    # Test failures
    errors+=$(echo "$logs" | grep -E "^(FAILED |E   |FAILED tests/)" || true)

    echo "$errors"
}

suggest_fixes() {
    local job_name="$1"
    local step_name="$2"
    local error_message="$3"

    echo ""
    echo -e "${BOLD}💡 Suggested Fixes:${NC}"
    echo ""

    # Python test failures
    if [[ $step_name =~ [Tt]est|pytest ]]; then
        echo -e "  ${GREEN}1.${NC} Run tests locally to reproduce:"
        echo -e "     ${CYAN}→ pytest -v tests/ -k \"<test_name>\"${NC}"
        echo ""
        echo -e "  ${GREEN}2.${NC} Check for missing fixtures or dependencies"
        echo ""
        echo -e "  ${GREEN}3.${NC} Review recent changes that may affect tests"
        echo ""
    fi

    # Linting errors
    if [[ $step_name =~ [Ll]int|ruff|flake8 ]]; then
        echo -e "  ${GREEN}1.${NC} Run linter locally:"
        echo -e "     ${CYAN}→ ruff check . --fix${NC}"
        echo ""
        echo -e "  ${GREEN}2.${NC} Review linting violations in the error output above"
        echo ""
    fi

    # Type checking errors
    if [[ $step_name =~ [Tt]ype|mypy ]]; then
        echo -e "  ${GREEN}1.${NC} Run type checker locally:"
        echo -e "     ${CYAN}→ mypy .${NC}"
        echo ""
        echo -e "  ${GREEN}2.${NC} Add missing type annotations"
        echo ""
    fi

    # Build failures
    if [[ $step_name =~ [Bb]uild|compile|install ]]; then
        echo -e "  ${GREEN}1.${NC} Check dependencies and versions"
        echo ""
        echo -e "  ${GREEN}2.${NC} Review package.json or requirements.txt"
        echo ""
        echo -e "  ${GREEN}3.${NC} Clear cache and reinstall:"
        echo -e "     ${CYAN}→ rm -rf node_modules package-lock.json && npm install${NC}"
        echo ""
    fi

    # ImportError
    if [[ $error_message =~ ImportError|ModuleNotFoundError ]]; then
        echo -e "  ${GREEN}1.${NC} Install missing package:"
        echo -e "     ${CYAN}→ pip install <package>${NC}"
        echo ""
        echo -e "  ${GREEN}2.${NC} Check requirements.txt for missing dependencies"
        echo ""
    fi

    # Generic advice
    echo -e "  ${GREEN}4.${NC} Review complete logs above for more context"
    echo ""
    echo -e "  ${GREEN}5.${NC} Check related jobs in the workflow run for patterns"
    echo ""
}

display_job_details() {
    local job_data="$1"
    local job_logs="$2"

    # Parse job metadata
    local job_id job_name workflow_name status conclusion started_at completed_at html_url run_id
    job_id=$(echo "$job_data" | jq -r '.id')
    job_name=$(echo "$job_data" | jq -r '.name')
    workflow_name=$(echo "$job_data" | jq -r '.workflow_name // "N/A"')
    status=$(echo "$job_data" | jq -r '.status')
    conclusion=$(echo "$job_data" | jq -r '.conclusion // "N/A"')
    started_at=$(echo "$job_data" | jq -r '.started_at')
    completed_at=$(echo "$job_data" | jq -r '.completed_at // .started_at')
    html_url=$(echo "$job_data" | jq -r '.html_url')
    run_id=$(echo "$job_data" | jq -r '.run_id')

    # Calculate duration
    local duration
    duration=$(format_duration "$started_at" "$completed_at")

    # Display header
    echo ""
    echo -e "${BOLD}╔════════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${BOLD}║${NC}           ${CYAN}${BOLD}CI JOB DETAILS${NC}                                    ${BOLD}║${NC}"
    echo -e "${BOLD}╚════════════════════════════════════════════════════════════════╝${NC}"
    echo ""

    # Job metadata
    echo -e "${BOLD}Job Information:${NC}"
    echo ""
    echo -e "  ${BLUE}Job ID:${NC} $job_id"
    echo -e "  ${BLUE}Job Name:${NC} $job_name"
    echo -e "  ${BLUE}Workflow:${NC} $workflow_name"
    echo -e "  ${BLUE}Status:${NC} $status"

    # Color code conclusion
    if [ "$conclusion" = "success" ]; then
        echo -e "  ${BLUE}Conclusion:${NC} ${GREEN}✓ $conclusion${NC}"
    elif [ "$conclusion" = "failure" ]; then
        echo -e "  ${BLUE}Conclusion:${NC} ${RED}✗ $conclusion${NC}"
    else
        echo -e "  ${BLUE}Conclusion:${NC} $conclusion"
    fi

    echo -e "  ${BLUE}Duration:${NC} $duration"
    echo -e "  ${BLUE}Started:${NC} $started_at"
    echo -e "  ${BLUE}Completed:${NC} $completed_at"
    echo ""
    echo -e "  ${BLUE}GitHub URL:${NC} ${CYAN}$html_url${NC}"
    echo ""

    # Display steps
    echo -e "${BOLD}Steps:${NC}"
    echo ""

    local steps
    steps=$(echo "$job_data" | jq -c '.steps[]')

    local step_number=1
    while IFS= read -r step; do
        local step_name step_status step_conclusion step_started step_completed step_number_display
        step_name=$(echo "$step" | jq -r '.name')
        step_status=$(echo "$step" | jq -r '.status')
        step_conclusion=$(echo "$step" | jq -r '.conclusion // "N/A"')
        step_started=$(echo "$step" | jq -r '.started_at // "N/A"')
        step_completed=$(echo "$step" | jq -r '.completed_at // .started_at')
        step_number_display=$(echo "$step" | jq -r '.number // 0')

        # Use JSON number if available, otherwise use our counter
        if [ "$step_number_display" -gt 0 ]; then
            step_number="$step_number_display"
        fi

        # Calculate step duration
        local step_duration="N/A"
        if [ "$step_started" != "N/A" ] && [ "$step_completed" != "N/A" ]; then
            step_duration=$(format_duration "$step_started" "$step_completed")
        fi

        # Color code by conclusion
        if [ "$step_conclusion" = "success" ]; then
            echo -e "  ${GREEN}${step_number}.${NC} ${step_name} ${GREEN}(✓ $step_conclusion, $step_duration)${NC}"
        elif [ "$step_conclusion" = "failure" ]; then
            echo -e "  ${RED}${step_number}.${NC} ${step_name} ${RED}(✗ $step_conclusion, $step_duration)${NC}"
        else
            echo -e "  ${step_number}. ${step_name} ($step_conclusion, $step_duration)"
        fi

        step_number=$((step_number + 1))
    done <<< "$steps"

    echo ""

    # Display failed steps with details
    local failed_steps
    failed_steps=$(echo "$job_data" | jq -c '.steps[] | select(.conclusion == "failure")')

    if [ -n "$failed_steps" ]; then
        echo -e "${BOLD}Failed Steps Details:${NC}"
        echo ""

        while IFS= read -r step; do
            local step_name step_number_display
            step_name=$(echo "$step" | jq -r '.name')
            step_number_display=$(echo "$step" | jq -r '.number // 0')

            echo -e "${RED}${BOLD}Step $step_number_display: $step_name${NC}"
            echo ""

            # Initialize errors variable before conditional block
            local errors=""

            # Extract error messages from logs
            if [ -n "$job_logs" ]; then
                # Find error patterns in logs
                errors=$(extract_error_patterns "$job_logs")

                if [ -n "$errors" ]; then
                    echo -e "${BOLD}Error Output:${NC}"
                    echo ""
                    echo -e "${RED}$errors${NC}" | head -50
                    echo ""
                fi
            else
                echo -e "${YELLOW}(Logs not available - may require authentication)${NC}"
                echo ""
            fi

            # Suggest fixes (errors may be empty if logs unavailable)
            suggest_fixes "$job_name" "$step_name" "$errors"

            echo ""
        done <<< "$failed_steps"
    fi

    # Display related jobs in workflow run
    echo -e "${BOLD}Related Jobs in Workflow Run:${NC}"
    echo ""

    local workflow_jobs
    workflow_jobs=$(fetch_workflow_run_jobs "$run_id")

    local job_count
    job_count=$(echo "$workflow_jobs" | jq '.jobs | length')

    if [ "$job_count" -gt 0 ]; then
        echo "$workflow_jobs" | jq -r '.jobs[] | "\(.id)|\(.name)|\(.conclusion // "N/A")"' | while IFS='|' read -r id name conclusion; do
            if [ "$conclusion" = "success" ]; then
                echo -e "  ${GREEN}●${NC} $name (Job ID: $id) - ${GREEN}✓ success${NC}"
            elif [ "$conclusion" = "failure" ]; then
                echo -e "  ${RED}●${NC} $name (Job ID: $id) - ${RED}✗ failure${NC}"
            else
                echo -e "  ${YELLOW}●${NC} $name (Job ID: $id) - $conclusion"
            fi
        done
    else
        echo -e "  ${YELLOW}(No related jobs found)${NC}"
    fi

    echo ""

    # Display complete logs section
    if [ -n "$job_logs" ]; then
        echo -e "${BOLD}Complete Job Logs:${NC}"
        echo ""
        echo -e "${CYAN}(Showing full logs - use scroll or pipe to less/more)${NC}"
        echo ""
        echo "─────────────────────────────────────────────────────────────────"
        echo "$job_logs"
        echo "─────────────────────────────────────────────────────────────────"
        echo ""
    fi

    # Display footer with links
    echo -e "${BOLD}─────────────────────────────────────────────────────────────────${NC}"
    echo ""
    echo -e "${BOLD}Next Steps:${NC}"
    echo ""
    echo -e "  ${GREEN}1.${NC} Review error details and suggested fixes above"
    echo -e "  ${GREEN}2.${NC} Reproduce failure locally using suggested commands"
    echo -e "  ${GREEN}3.${NC} Check related jobs for patterns"
    echo -e "  ${GREEN}4.${NC} View job on GitHub: ${CYAN}$html_url${NC}"
    echo ""
    echo -e "${BOLD}─────────────────────────────────────────────────────────────────${NC}"
    echo ""
}

# ============================================================================
# Main Script
# ============================================================================

# Check for help flag
if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    usage
fi

# Check dependencies
check_dependencies

# Get repository info
get_repo_info

# Parse arguments
if [ $# -lt 1 ]; then
    print_error "Missing required argument: JOB_ID or JOB_URL"
    echo "" >&2
    echo "Usage: $(basename "$0") <JOB_ID|JOB_URL> [PR_NUMBER]" >&2
    exit 1
fi

# Extract job ID from first argument
extract_job_id "$1"

# Optional PR number
if [ $# -ge 2 ]; then
    PR_NUMBER="$2"
    print_status "PR context: #$PR_NUMBER"
fi

# Fetch job details
print_status "Fetching details for job: $JOB_ID"
job_data=$(fetch_job_details "$JOB_ID")

# Fetch job logs
job_logs=$(fetch_job_logs "$JOB_ID")

# Display formatted output
display_job_details "$job_data" "$job_logs"

print_success "Job details investigation complete"
exit 0
