#!/bin/bash
# =============================================================================
# AuctionForge Cron Setup
# Single script to install, remove, check status, and test the AuctionForge
# external cron system. Ships with the plugin and can be run from any site.
#
# Usage:
#   bash setup.sh install          Install everything (script, dirs, all crontab entries)
#   bash setup.sh install --only importData,importBidSpirit
#                                  Install only specific tasks
#   bash setup.sh remove           Remove all crontab entries (keeps logs)
#   bash setup.sh remove --purge   Remove entries + script + logs + locks
#   bash setup.sh status           Show full cron system status
#   bash setup.sh test [task]      Run a single task for this site only (dry-run safe)
#   bash setup.sh help             Show this help
#
# Can also be run after install from:
#   /www/server/cron/auctionforge-cron-setup.sh <command>
# =============================================================================

set -euo pipefail

# ─── Configuration ───────────────────────────────────────────────────────────
CRON_RUNNER="auctionforge-cron.sh"
CRON_SETUP="auctionforge-cron-setup.sh"
INSTALL_DIR="/www/server/cron"
LOG_DIR="/var/log/auctionforge-cron"
LOCK_DIR="/tmp/auctionforge-cron-locks"
PHP_BIN="/www/server/php/83/bin/php"
WWWROOT="/www/wwwroot"
PLUGIN_DIRS=("auctionforge" "uco-auctions")

# Where is the cron runner source? (next to this script in the plugin)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# The cron runner source lives one level up from crontasks/ at the plugin root,
# but we generate it in-place if not found
RUNNER_SOURCE=""

# ─── Color helpers ───────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m' # No Color

ok()   { echo -e "  ${GREEN}✓${NC} $1"; }
warn() { echo -e "  ${YELLOW}⚠${NC} $1"; }
err()  { echo -e "  ${RED}✗${NC} $1"; }
info() { echo -e "  ${BLUE}ℹ${NC} $1"; }
header() { echo -e "\n${BOLD}${CYAN}─── $1 ───${NC}"; }

# ─── Task definitions (crontab schedule + runner args) ───────────────────────
# Format: "schedule|task_name|description"
ALL_TASKS=(
    "*/1 * * * *|importData|Process import queue into WP posts (every minute)"
    "5 * * * *|importBidSpirit|Sync upcoming auctions + lots from BidSpirit (hourly)"
    "0 3 * * *|lotBidSpiritOld|Sync archived/past auctions (daily at 3am)"
    "0 4 * * 0|cleaner|Clean draft/trash lot posts (weekly Sunday 4am)"
    "30 4 * * 0|cleanerTrashMeta|Clean orphaned meta fields (weekly Sunday 4:30am)"
)

# ─── Helpers ─────────────────────────────────────────────────────────────────

find_runner_source() {
    # Check if the runner exists in the install dir already
    if [[ -f "$INSTALL_DIR/$CRON_RUNNER" ]]; then
        RUNNER_SOURCE="$INSTALL_DIR/$CRON_RUNNER"
        return 0
    fi
    # Check legacy name
    if [[ -f "$INSTALL_DIR/uco-auctions-cron.sh" ]]; then
        RUNNER_SOURCE="$INSTALL_DIR/uco-auctions-cron.sh"
        return 0
    fi
    return 1
}

get_task_names() {
    local names=""
    for entry in "${ALL_TASKS[@]}"; do
        IFS='|' read -r _ name _ <<< "$entry"
        names="$names $name"
    done
    echo "$names" | xargs
}

count_sites() {
    local count=0
    for plugin_dir in "${PLUGIN_DIRS[@]}"; do
        local found
        found=$(find "$WWWROOT" -maxdepth 5 -path "*/plugins/${plugin_dir}/crontasks" -type d 2>/dev/null | wc -l)
        count=$((count + found))
    done
    echo "$count"
}

list_sites() {
    for plugin_dir in "${PLUGIN_DIRS[@]}"; do
        find "$WWWROOT" -maxdepth 5 -path "*/plugins/${plugin_dir}/crontasks" -type d 2>/dev/null | while read crontasks_dir; do
            local site_dir
            site_dir=$(echo "$crontasks_dir" | sed "s|/wp-content/plugins/${plugin_dir}/crontasks||")
            basename "$site_dir"
        done
    done | sort -u
}

current_crontab_entries() {
    crontab -l 2>/dev/null | grep -c "auctionforge-cron\|uco-auctions-cron" || echo "0"
}

# ─── Commands ────────────────────────────────────────────────────────────────

cmd_install() {
    local only_tasks=""

    # Parse --only flag
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --only)
                only_tasks="$2"
                shift 2
                ;;
            *)
                shift
                ;;
        esac
    done

    header "AuctionForge Cron Setup — Install"

    # 1. Create directories
    echo -e "\n${BOLD}1. Creating directories${NC}"
    mkdir -p "$INSTALL_DIR" && ok "Cron directory: $INSTALL_DIR"
    mkdir -p "$LOG_DIR" && ok "Log directory:  $LOG_DIR"
    mkdir -p "$LOCK_DIR" && ok "Lock directory: $LOCK_DIR"

    # 2. Install cron runner script
    echo -e "\n${BOLD}2. Installing cron runner${NC}"
    if find_runner_source; then
        if [[ "$RUNNER_SOURCE" != "$INSTALL_DIR/$CRON_RUNNER" ]]; then
            cp "$RUNNER_SOURCE" "$INSTALL_DIR/$CRON_RUNNER"
            ok "Copied runner to $INSTALL_DIR/$CRON_RUNNER"
        else
            ok "Runner already at $INSTALL_DIR/$CRON_RUNNER"
        fi
    else
        err "Cron runner script not found. Expected at $INSTALL_DIR/$CRON_RUNNER"
        err "Please copy the cron runner script manually first."
        exit 1
    fi
    chmod +x "$INSTALL_DIR/$CRON_RUNNER"
    ok "Set executable permissions"

    # 3. Install this setup script too
    local self_path
    self_path="$(realpath "$0")"
    if [[ "$self_path" != "$INSTALL_DIR/$CRON_SETUP" ]]; then
        cp "$self_path" "$INSTALL_DIR/$CRON_SETUP"
        chmod +x "$INSTALL_DIR/$CRON_SETUP"
        ok "Setup script installed to $INSTALL_DIR/$CRON_SETUP"
    fi

    # 4. Verify PHP binary
    echo -e "\n${BOLD}3. Checking PHP${NC}"
    if [[ -x "$PHP_BIN" ]]; then
        local php_ver
        php_ver=$("$PHP_BIN" -v 2>/dev/null | head -1 | awk '{print $2}')
        ok "PHP $php_ver at $PHP_BIN"
    else
        warn "PHP not found at $PHP_BIN — edit CRON_RUNNER config section"
    fi

    # 5. Discover sites
    echo -e "\n${BOLD}4. Discovering sites${NC}"
    local site_count
    site_count=$(count_sites)
    if [[ "$site_count" -gt 0 ]]; then
        ok "Found $site_count site(s) with AuctionForge:"
        list_sites | while read site; do
            echo -e "     ${DIM}•${NC} $site"
        done
    else
        warn "No sites found with AuctionForge plugin in $WWWROOT"
    fi

    # 6. Set up crontab entries
    echo -e "\n${BOLD}5. Configuring crontab${NC}"

    # Get current crontab (without our entries)
    local current_cron
    current_cron=$(crontab -l 2>/dev/null | grep -v "auctionforge-cron\|uco-auctions-cron" || true)

    # Build new entries
    local new_entries=""
    local installed_count=0

    # Filter tasks if --only specified
    local task_filter=""
    if [[ -n "$only_tasks" ]]; then
        task_filter="$only_tasks"
        info "Installing only: $task_filter"
    fi

    for entry in "${ALL_TASKS[@]}"; do
        IFS='|' read -r schedule task_name desc <<< "$entry"

        # Skip if --only specified and this task isn't in the list
        if [[ -n "$task_filter" ]]; then
            if ! echo ",$task_filter," | grep -q ",$task_name,"; then
                continue
            fi
        fi

        local cron_line="$schedule $INSTALL_DIR/$CRON_RUNNER $task_name >> $LOG_DIR/${task_name}_cron.log 2>&1"
        new_entries="${new_entries}${cron_line}\n"
        installed_count=$((installed_count + 1))
        ok "$task_name — $desc"
        echo -e "     ${DIM}$schedule${NC}"
    done

    # Also preserve any --only tasks that were already in crontab but not in current install set
    if [[ -n "$task_filter" ]]; then
        # Keep existing auctionforge entries for tasks NOT in the --only list
        local existing_af_entries
        existing_af_entries=$(crontab -l 2>/dev/null | grep "auctionforge-cron" || true)
        while IFS= read -r line; do
            [[ -z "$line" ]] && continue
            local keep=true
            for entry in "${ALL_TASKS[@]}"; do
                IFS='|' read -r _ task_name _ <<< "$entry"
                if echo ",$task_filter," | grep -q ",$task_name,"; then
                    if echo "$line" | grep -q "$task_name"; then
                        keep=false  # This task is being replaced
                        break
                    fi
                fi
            done
            if $keep; then
                new_entries="${new_entries}${line}\n"
            fi
        done <<< "$existing_af_entries"
    fi

    # Write crontab
    if [[ $installed_count -gt 0 ]]; then
        echo -e "${current_cron}\n# --- AuctionForge Cron Tasks ---\n$(echo -e "$new_entries")" | crontab -
        ok "Crontab updated with $installed_count task(s)"
    else
        warn "No tasks to install"
    fi

    # 7. Summary
    header "Setup Complete"
    echo ""
    echo -e "  ${GREEN}${BOLD}AuctionForge cron system is ready.${NC}"
    echo ""
    echo -e "  Runner:   ${CYAN}$INSTALL_DIR/$CRON_RUNNER${NC}"
    echo -e "  Logs:     ${CYAN}$LOG_DIR/${NC}"
    echo -e "  Locks:    ${CYAN}$LOCK_DIR/${NC}"
    echo -e "  Sites:    ${CYAN}$site_count${NC}"
    echo -e "  Tasks:    ${CYAN}$installed_count${NC}"
    echo ""
    echo -e "  ${DIM}Run '$(basename "$0") status' to verify, or '$(basename "$0") test importData' to test.${NC}"
    echo ""
}

cmd_remove() {
    local purge=false
    [[ "${1:-}" == "--purge" ]] && purge=true

    header "AuctionForge Cron Setup — Remove"

    # Remove crontab entries
    echo -e "\n${BOLD}1. Removing crontab entries${NC}"
    local count_before
    count_before=$(current_crontab_entries)
    local cleaned_cron
    cleaned_cron=$(crontab -l 2>/dev/null | grep -v "auctionforge-cron\|uco-auctions-cron\|# --- AuctionForge" || true)
    echo "$cleaned_cron" | crontab -
    ok "Removed $count_before cron entries"

    if $purge; then
        echo -e "\n${BOLD}2. Purging files${NC}"

        if [[ -f "$INSTALL_DIR/$CRON_RUNNER" ]]; then
            rm -f "$INSTALL_DIR/$CRON_RUNNER"
            ok "Removed $INSTALL_DIR/$CRON_RUNNER"
        fi
        if [[ -f "$INSTALL_DIR/$CRON_SETUP" ]]; then
            rm -f "$INSTALL_DIR/$CRON_SETUP"
            ok "Removed $INSTALL_DIR/$CRON_SETUP"
        fi
        # Legacy
        if [[ -f "$INSTALL_DIR/uco-auctions-cron.sh" ]]; then
            rm -f "$INSTALL_DIR/uco-auctions-cron.sh"
            ok "Removed legacy uco-auctions-cron.sh"
        fi

        if [[ -d "$LOG_DIR" ]]; then
            rm -rf "$LOG_DIR"
            ok "Removed log directory $LOG_DIR"
        fi
        if [[ -d "$LOCK_DIR" ]]; then
            rm -rf "$LOCK_DIR"
            ok "Removed lock directory $LOCK_DIR"
        fi
        # Legacy dirs
        rm -rf /var/log/uco-auctions-cron /tmp/uco-cron-locks 2>/dev/null && ok "Removed legacy directories" || true
    else
        info "Logs and scripts kept. Use 'remove --purge' to delete everything."
    fi

    echo ""
    ok "AuctionForge cron entries removed."
    echo ""
}

cmd_status() {
    header "AuctionForge Cron Status"

    # Runner script
    echo -e "\n${BOLD}Cron Runner${NC}"
    if [[ -f "$INSTALL_DIR/$CRON_RUNNER" ]]; then
        ok "Installed at $INSTALL_DIR/$CRON_RUNNER"
        if [[ -x "$INSTALL_DIR/$CRON_RUNNER" ]]; then
            ok "Executable"
        else
            warn "Not executable — run: chmod +x $INSTALL_DIR/$CRON_RUNNER"
        fi
    else
        err "Not installed at $INSTALL_DIR/$CRON_RUNNER"
    fi

    # PHP
    echo -e "\n${BOLD}PHP${NC}"
    if [[ -x "$PHP_BIN" ]]; then
        local php_ver
        php_ver=$("$PHP_BIN" -v 2>/dev/null | head -1 | awk '{print $2}')
        ok "PHP $php_ver at $PHP_BIN"
    else
        err "PHP not found at $PHP_BIN"
    fi

    # Directories
    echo -e "\n${BOLD}Directories${NC}"
    [[ -d "$LOG_DIR" ]] && ok "Logs:  $LOG_DIR" || err "Logs:  $LOG_DIR (missing)"
    [[ -d "$LOCK_DIR" ]] && ok "Locks: $LOCK_DIR" || err "Locks: $LOCK_DIR (missing)"

    # Log sizes
    if [[ -d "$LOG_DIR" ]]; then
        local log_size
        log_size=$(du -sh "$LOG_DIR" 2>/dev/null | awk '{print $1}')
        info "Total log size: $log_size"
    fi

    # Sites
    echo -e "\n${BOLD}Discovered Sites${NC}"
    local site_count
    site_count=$(count_sites)
    if [[ "$site_count" -gt 0 ]]; then
        ok "$site_count site(s) found:"
        list_sites | while read site; do
            echo -e "     ${DIM}•${NC} $site"
        done
    else
        warn "No sites found"
    fi

    # Crontab
    echo -e "\n${BOLD}Crontab Entries${NC}"
    local cron_lines
    cron_lines=$(crontab -l 2>/dev/null | grep "auctionforge-cron\|uco-auctions-cron" || true)
    if [[ -n "$cron_lines" ]]; then
        local count
        count=$(echo "$cron_lines" | wc -l)
        ok "$count entries configured:"
        echo "$cron_lines" | while IFS= read -r line; do
            # Extract task name
            local task
            task=$(echo "$line" | grep -oP '(?<=auctionforge-cron\.sh |uco-auctions-cron\.sh )\S+')
            echo -e "     ${GREEN}●${NC} $task"
            echo -e "       ${DIM}$line${NC}"
        done
    else
        err "No crontab entries found"
    fi

    # Active locks
    echo -e "\n${BOLD}Active Locks${NC}"
    if [[ -d "$LOCK_DIR" ]]; then
        local lock_count
        lock_count=$(find "$LOCK_DIR" -name "*.lock" 2>/dev/null | wc -l)
        if [[ "$lock_count" -gt 0 ]]; then
            warn "$lock_count active lock(s):"
            find "$LOCK_DIR" -name "*.lock" -printf "     %f (age: %Ts)\n" 2>/dev/null
        else
            ok "No active locks"
        fi
    else
        info "Lock directory doesn't exist yet"
    fi

    # Last runs (today's logs)
    echo -e "\n${BOLD}Last Run Status${NC}"
    local today
    today=$(date +%Y-%m-%d)
    for entry in "${ALL_TASKS[@]}"; do
        IFS='|' read -r _ task_name desc <<< "$entry"
        local logfile="$LOG_DIR/${task_name}_${today}.log"
        if [[ -f "$logfile" ]]; then
            local last_line
            last_line=$(grep -E "run finished|DONE|FAILED|TIMEOUT" "$logfile" 2>/dev/null | tail -1)
            if [[ -n "$last_line" ]]; then
                if echo "$last_line" | grep -qE "FAILED|TIMEOUT|errors"; then
                    if echo "$last_line" | grep -q "0 errors"; then
                        ok "$task_name: $(echo "$last_line" | sed 's/.*\] //')"
                    else
                        warn "$task_name: $(echo "$last_line" | sed 's/.*\] //')"
                    fi
                else
                    ok "$task_name: $(echo "$last_line" | sed 's/.*\] //')"
                fi
            else
                info "$task_name: log exists but no completion entry"
            fi
        else
            echo -e "  ${DIM}–${NC} $task_name: no log for today"
        fi
    done

    echo ""
}

cmd_test() {
    local task="${1:-importData}"
    local valid_tasks
    valid_tasks=$(get_task_names)

    if ! echo "$valid_tasks" | grep -qw "$task"; then
        err "Unknown task '$task'. Valid: $valid_tasks"
        exit 1
    fi

    header "AuctionForge Cron Test — $task"

    if [[ ! -f "$INSTALL_DIR/$CRON_RUNNER" ]]; then
        err "Cron runner not installed. Run 'install' first."
        exit 1
    fi

    # Detect current site from script location
    local site=""
    local current_dir="$SCRIPT_DIR"
    if echo "$current_dir" | grep -q "$WWWROOT"; then
        site=$(echo "$current_dir" | sed "s|$WWWROOT/||" | cut -d'/' -f1)
    fi

    if [[ -n "$site" ]]; then
        info "Testing task '$task' for site: $site"
        echo ""
        "$INSTALL_DIR/$CRON_RUNNER" "$task" --site "$site"
    else
        info "Could not detect site. Running for ALL sites."
        echo ""
        "$INSTALL_DIR/$CRON_RUNNER" "$task"
    fi

    echo ""
    ok "Test complete. Check logs at: $LOG_DIR/${task}_$(date +%Y-%m-%d).log"
    echo ""
}

cmd_help() {
    echo -e "${BOLD}${CYAN}"
    echo "  ┌─────────────────────────────────────────┐"
    echo "  │       AuctionForge Cron Setup            │"
    echo "  └─────────────────────────────────────────┘"
    echo -e "${NC}"
    echo -e "  ${BOLD}Usage:${NC} $(basename "$0") <command> [options]"
    echo ""
    echo -e "  ${BOLD}Commands:${NC}"
    echo -e "    ${GREEN}install${NC}              Install everything (script, dirs, all crontab entries)"
    echo -e "    ${GREEN}install --only${NC} list  Install specific tasks only (comma-separated)"
    echo -e "    ${GREEN}remove${NC}               Remove crontab entries (keeps logs/script)"
    echo -e "    ${GREEN}remove --purge${NC}       Remove everything including logs and scripts"
    echo -e "    ${GREEN}status${NC}               Show full cron system status"
    echo -e "    ${GREEN}test${NC} [task]           Run a task once for this site (default: importData)"
    echo -e "    ${GREEN}help${NC}                 Show this help"
    echo ""
    echo -e "  ${BOLD}Available tasks:${NC}"
    for entry in "${ALL_TASKS[@]}"; do
        IFS='|' read -r schedule task_name desc <<< "$entry"
        printf "    ${CYAN}%-20s${NC} %s\n" "$task_name" "$desc"
    done
    echo ""
    echo -e "  ${BOLD}Examples:${NC}"
    echo -e "    ${DIM}# Full install — one command, everything set up${NC}"
    echo -e "    bash setup.sh install"
    echo ""
    echo -e "    ${DIM}# Install only import tasks${NC}"
    echo -e "    bash setup.sh install --only importData,importBidSpirit"
    echo ""
    echo -e "    ${DIM}# Check what's running${NC}"
    echo -e "    bash setup.sh status"
    echo ""
    echo -e "    ${DIM}# Test a specific task on this site${NC}"
    echo -e "    bash setup.sh test importBidSpirit"
    echo ""
    echo -e "    ${DIM}# Full removal${NC}"
    echo -e "    bash setup.sh remove --purge"
    echo ""
}

# ─── Main ────────────────────────────────────────────────────────────────────

COMMAND="${1:-help}"
shift 2>/dev/null || true

case "$COMMAND" in
    install)  cmd_install "$@" ;;
    remove)   cmd_remove "$@" ;;
    status)   cmd_status ;;
    test)     cmd_test "$@" ;;
    help|-h|--help) cmd_help ;;
    *)
        err "Unknown command '$COMMAND'"
        echo ""
        cmd_help
        exit 1
        ;;
esac
