#!/bin/bash
# PR Review Daemon (Improved)
# Polls GitHub for new PRs, performs code review, posts to Feishu
#
# Usage:
#   bash run.sh start   - Start daemon
#   bash run.sh stop    - Stop daemon
#   bash run.sh status  - Check status
#   bash run.sh once    - Single poll (testing)

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PID_FILE="/tmp/pr-review-daemon.pid"
LOG_FILE="/tmp/pr-review-daemon.log"
STATE_FILE="$HOME/.openclaw/pr-review-daemon-state.json"

# Load config
CONFIG_FILE="${CONFIG_FILE:-$HOME/.config/team-code-expert/config.env}"
[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"

# Required config
: "${GITHUB_APP_ID:?ERROR: GITHUB_APP_ID not set}"
: "${GITHUB_INSTALLATION_ID:?ERROR: GITHUB_INSTALLATION_ID not set}"
GITHUB_PRIVATE_KEY="${GITHUB_PRIVATE_KEY:-$HOME/.ssh/github-app.pem}"
GITHUB_TOKEN_FILE="$HOME/.ssh/gh-app-token"

: "${FEISHU_APP_ID:?ERROR: FEISHU_APP_ID not set}"
: "${FEISHU_APP_SECRET:?ERROR: FEISHU_APP_SECRET not set}"
: "${FEISHU_CHAT_ID:?ERROR: FEISHU_CHAT_ID not set}"
FEISHU_BOT_OPEN_ID="${FEISHU_BOT_OPEN_ID:-}"

POLL_INTERVAL="${POLL_INTERVAL:-60}"
GITHUB_ORG="tidbcloud"
WATCH_REPOS="dataflow-service data-service-infra-ai-configurations"
LOCAL_REPOS_DIR="$HOME/github"

#=============================================================================
# State Management
#=============================================================================

init_state() {
    mkdir -p "$(dirname "$STATE_FILE")"
    [ ! -f "$STATE_FILE" ] && echo '{"prs":{}}' > "$STATE_FILE"
}

is_processed() {
    local key="$1"
    grep -q "\"$key\"" "$STATE_FILE" 2>/dev/null
}

mark_processed() {
    local key="$1" tmp=$(mktemp)
    # Escape key for sed (handle special chars)
    local escaped_key=$(echo "$key" | sed 's/\[/\\[/g; s/\]/\\]/g; s/\./\\./g')
    if grep -q '"prs":{}' "$STATE_FILE"; then
        sed "s|\"prs\":{}|\"prs\":{\"$escaped_key\":$(date +%s)}|" "$STATE_FILE" > "$tmp"
    else
        sed "s|\"prs\":{|\"prs\":{\"$escaped_key\":$(date +%s),|" "$STATE_FILE" > "$tmp"
    fi
    mv "$tmp" "$STATE_FILE"
}

#=============================================================================
# GitHub API
#=============================================================================

get_github_token() {
    # Check cache (valid for 30 min)
    if [ -f "$GITHUB_TOKEN_FILE" ]; then
        local age=$(($(date +%s) - $(stat -c %Y "$GITHUB_TOKEN_FILE" 2>/dev/null || echo 0)))
        [ $age -lt 1800 ] && { cat "$GITHUB_TOKEN_FILE"; return; }
    fi
    
    [ ! -f "$GITHUB_PRIVATE_KEY" ] && { log "ERROR: Private key not found"; return 1; }
    
    # Generate JWT
    local now=$(date +%s)
    local h=$(echo -n '{"alg":"RS256","typ":"JWT"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
    local p=$(echo -n "{\"iat\":$((now-60)),\"exp\":$((now+600)),\"iss\":\"$GITHUB_APP_ID\"}" | base64 -w0 | tr '+/' '-_' | tr -d '=')
    local s=$(echo -n "$h.$p" | openssl dgst -sha256 -sign "$GITHUB_PRIVATE_KEY" | base64 -w0 | tr '+/' '-_' | tr -d '=')
    
    local token=$(curl -s -X POST \
        -H "Authorization: Bearer $h.$p.$s" \
        -H "Accept: application/vnd.github+json" \
        "https://api.github.com/app/installations/$GITHUB_INSTALLATION_ID/access_tokens" \
        | sed -n 's/.*"token": *"\([^"]*\)".*/\1/p')
    
    [ -n "$token" ] && { echo "$token" > "$GITHUB_TOKEN_FILE"; echo "$token"; }
}

get_pr_info() {
    local token="$1" repo="$2" pr="$3"
    curl -s -H "Authorization: token $token" -H "Accept: application/vnd.github+json" \
        "https://api.github.com/repos/$GITHUB_ORG/$repo/pulls/$pr"
}

get_pr_diff() {
    local token="$1" repo="$2" pr="$3"
    curl -s -H "Authorization: token $token" -H "Accept: application/vnd.github.v3.diff" \
        "https://api.github.com/repos/$GITHUB_ORG/$repo/pulls/$pr"
}

get_pr_files() {
    local token="$1" repo="$2" pr="$3"
    curl -s -H "Authorization: token $token" -H "Accept: application/vnd.github+json" \
        "https://api.github.com/repos/$GITHUB_ORG/$repo/pulls/$pr/files?per_page=50"
}

#=============================================================================
# Feishu API
#=============================================================================

get_feishu_token() {
    curl -s -X POST -H "Content-Type: application/json" \
        -d "{\"app_id\":\"$FEISHU_APP_ID\",\"app_secret\":\"$FEISHU_APP_SECRET\"}" \
        "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
        | sed -n 's/.*"tenant_access_token": *"\([^"]*\)".*/\1/p'
}

send_feishu_text() {
    local token="$1" text="$2"
    
    # Escape for JSON
    local escaped=$(printf '%s' "$text" | sed ':a;N;$!ba;s/\\/\\\\/g;s/"/\\"/g;s/\n/\\\\n/g')
    
    curl -s -X POST \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        -d "{\"receive_id\":\"$FEISHU_CHAT_ID\",\"msg_type\":\"text\",\"content\":\"{\\\"text\\\":\\\"$escaped\\\"}\"}" \
        "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id" \
        > /dev/null 2>&1
}

send_feishu_with_mention() {
    local token="$1" text="$2"
    
    # Add @mention to the beginning of the message
    if [ -n "$FEISHU_BOT_OPEN_ID" ]; then
        # Use Feishu mention syntax: <at id=ou_xxx></at>
        local mention="<at id=$FEISHU_BOT_OPEN_ID></at>\n"
        text="$mention$text"
    fi
    
    send_feishu_text "$token" "$text"
}

#=============================================================================
# Code Analysis
#=============================================================================

analyze_pr() {
    local repo="$1" pr="$2" diff="$3" files_json="$4"
    
    # Get file list
    local file_list=$(echo "$diff" | grep '^diff --git' | sed 's|diff --git a/||; s| b/.*||' | head -15)
    local file_count=$(echo "$file_list" | wc -l)
    
    # Count changes
    local added=$(echo "$diff" | grep -c '^+[^+]' || echo 0)
    local removed=$(echo "$diff" | grep -c '^-[^-]' || echo 0)
    
    # Build analysis
    local analysis="📊 PR Analysis

"
    
    # File summary
    analysis="$analysis📁 Changed files ($file_count):
"
    echo "$file_list" | while read -r f; do
        [ -n "$f" ] && analysis="$analysis  • $f"
    done
    analysis="$analysis

📈 Code stats:
  • Added: +$added lines
  • Removed: -$removed lines

"

    # Check for common issues
    local issues=""
    
    # TODO/FIXME
    if echo "$diff" | grep -qE 'TODO|FIXME|XXX|HACK'; then
        issues="$issues⚠️  Contains TODO/FIXME comments
"
    fi
    
    # Hardcoded secrets (basic check)
    if echo "$diff" | grep -E '(password|secret|token|api_key|apikey)\s*[=:]\s*["\x27][^"\x27]{8,}["\x27]' | grep -vE '(your_|example|placeholder|template|<|YOUR_|xxx)' > /dev/null 2>&1; then
        issues="$issues⚠️  May contain hardcoded secrets
"
    fi
    
    # Large PR
    if [ "$added" -gt 1000 ]; then
        issues="$issuesℹ️  Large PR (+$added lines), consider splitting
"
    fi
    
    # Many files
    if [ "$file_count" -gt 20 ]; then
        issues="$issuesℹ️  Many files changed ($file_count)
"
    fi
    
    # Security-sensitive changes
    if echo "$diff" | grep -qE '(chmod|chown|sudo|eval|exec|system|password|auth|login)' > /dev/null 2>&1; then
        issues="$issues🔒  Security-sensitive changes detected
"
    fi
    
    if [ -n "$issues" ]; then
        analysis="$analysis⚠️  Notes:
$issues"
    else
        analysis="$analysis✅ No obvious issues found"
    fi
    
    echo "$analysis"
}

#=============================================================================
# Main Logic
#=============================================================================

log() {
    echo "[$(date -Iseconds)] $1"
}

process_pr() {
    local gh_token="$1" feishu_token="$2" repo="$3" pr="$4" title="$5" author="$6" url="$7"
    local pr_key="${repo}#${pr}"
    
    log "Processing $pr_key: $title"
    
    # Get diff and files
    local diff=$(get_pr_diff "$gh_token" "$repo" "$pr")
    local files_json=$(get_pr_files "$gh_token" "$repo" "$pr")
    
    # Perform basic analysis
    local analysis=$(analyze_pr "$repo" "$pr" "$diff" "$files_json")
    
    # Send notification with @mention to trigger AI
    local notify_msg="@data-service-code-expert

🔔 New PR detected!

📦 Repo: $repo
🔢 PR: #$pr
📋 Title: $title
👤 Author: $author
🔗 $url

⏳ Reviewing..."
    
    send_feishu_with_mention "$feishu_token" "$notify_msg"
    log "Sent notification for $pr_key"
    
    # Write to queue for AI processing (in case @mention doesn't work)
    local queue_file="$HOME/.openclaw/pr-review-queue.txt"
    mkdir -p "$(dirname "$queue_file")"
    echo "$repo|$pr|$title|$author|$url" >> "$queue_file"
    log "Added $pr_key to queue"
    
    # Mark as processed
    mark_processed "$pr_key"
    
    # Send analysis result
    sleep 3
    local result_msg="$analysis

---
💡 For detailed AI review, please mention @data-service-code-expert"
    send_feishu_text "$feishu_token" "$result_msg"
}

poll_once() {
    log "Polling..."
    
    local gh_token=$(get_github_token)
    [ -z "$gh_token" ] && { log "ERROR: No GitHub token"; return 1; }
    
    local feishu_token=$(get_feishu_token)
    [ -z "$feishu_token" ] && { log "ERROR: No Feishu token"; return 1; }
    
    # Only process PRs created in last 10 minutes
    local cutoff_time=$(($(date +%s) - 600))
    
    for repo in $WATCH_REPOS; do
        local prs=$(curl -s -H "Authorization: token $gh_token" \
            "https://api.github.com/repos/$GITHUB_ORG/$repo/pulls?state=open&sort=created&direction=desc&per_page=10")
        
        [ -z "$prs" ] || [ "$prs" = "[]" ] && continue
        
        echo "$prs" > /tmp/prs_$$.json
        local numbers=$(grep -o '"number": *[0-9]*' /tmp/prs_$$.json | grep -o '[0-9]*')
        
        for pr in $numbers; do
            local pr_key="${repo}#${pr}"
            
            is_processed "$pr_key" && continue
            
            local info=$(get_pr_info "$gh_token" "$repo" "$pr")
            
            local title=$(echo "$info" | sed -n 's/.*"title": *"\([^"]*\)".*/\1/p' | head -1)
            local author=$(echo "$info" | sed -n 's/.*"login": *"\([^"]*\)".*/\1/p' | head -1)
            local created_at=$(echo "$info" | sed -n 's/.*"created_at": *"\([^"]*\)".*/\1/p' | head -1)
            local url="https://github.com/$GITHUB_ORG/$repo/pull/$pr"
            
            local created_ts=$(date -d "$created_at" +%s 2>/dev/null || echo 0)
            if [ "$created_ts" -lt "$cutoff_time" ]; then
                mark_processed "$pr_key"
                log "Skipped old PR: $pr_key"
                continue
            fi
            
            log "New PR found: $pr_key - $title"
            process_pr "$gh_token" "$feishu_token" "$repo" "$pr" "$title" "$author" "$url"
            
            sleep 2
        done
        
        rm -f /tmp/prs_$$.json
    done
    
    log "Poll complete"
}

daemon_loop() {
    log "Daemon started (interval: ${POLL_INTERVAL}s)"
    log "Watching: $WATCH_REPOS"
    init_state
    
    while true; do
        poll_once || true
        sleep "$POLL_INTERVAL"
    done
}

#=============================================================================
# Daemon Control
#=============================================================================

start_daemon() {
    if [ -f "$PID_FILE" ]; then
        local pid=$(cat "$PID_FILE")
        if kill -0 "$pid" 2>/dev/null; then
            echo "Already running (PID: $pid)"
            return 1
        fi
        rm -f "$PID_FILE"
    fi
    
    init_state
    nohup bash "$0" _daemon > "$LOG_FILE" 2>&1 &
    echo $! > "$PID_FILE"
    echo "Started (PID: $!, Log: $LOG_FILE)"
}

stop_daemon() {
    if [ ! -f "$PID_FILE" ]; then
        echo "Not running"
        return 0
    fi
    
    local pid=$(cat "$PID_FILE")
    if kill "$pid" 2>/dev/null; then
        echo "Stopped (PID: $pid)"
    else
        echo "Not running (stale PID)"
    fi
    rm -f "$PID_FILE"
}

check_status() {
    if [ -f "$PID_FILE" ]; then
        local pid=$(cat "$PID_FILE")
        if kill -0 "$pid" 2>/dev/null; then
            echo "Running (PID: $pid)"
            echo "Log: $LOG_FILE"
            echo ""
            echo "Recent logs:"
            tail -10 "$LOG_FILE" 2>/dev/null
            return 0
        fi
    fi
    echo "Not running"
}

case "${1:-}" in
    start)   start_daemon ;;
    stop)    stop_daemon ;;
    status)  check_status ;;
    once)    init_state; poll_once ;;
    _daemon) daemon_loop ;;
    *)       echo "Usage: $0 {start|stop|status|once}"; exit 1 ;;
esac
