#!/usr/bin/env bash
#
# homelab-infrastructure-review.sh
# Triggers a full 3-way infrastructure reconciliation audit.
# Audits Infra.md ↔ Live Docker ↔ Homelable Canvas ↔ Homepage Dashboard.
# Triggered ONLY by explicit, manual user request. No cron or automation.
#
# Usage: bash /srv/configs/ai/skills/homelab-infrastructure-review/scripts/homelab-infrastructure-review.sh [--dry-run]
#

set -euo pipefail

CONF_DIR="/srv/configs/ai"
INFRA_FILE="/srv/docs/public/projects/homelab/homelab_Infra.md"
MCP_ENDPOINT="http://localhost:9445/api/v1"
ALIAS_FILE="/srv/configs/.bash_aliases"
LOCK_FILE="/srv/configs/ai/.audit.lock"
HOMEPAGE_FILE="/srv/configs/docker_compose/homepage/config/services.yaml"
DRY_RUN=false

if [[ "${1:-}" == "--dry-run" ]]; then
    DRY_RUN=true
fi

# ── Logging helpers ──────────────────────────────────────────────────────────

log_info() {
    local msg="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $*"
    echo "$msg"
}

log_error() {
    local msg="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $*"
    echo "$msg" >&2
}

# ── Lock (prevent concurrent runs) ───────────────────────────────────────────

acquire_lock() {
    if [ -f "$LOCK_FILE" ]; then
        local lock_pid
        lock_pid=$(cat "$LOCK_FILE" 2>/dev/null || echo "")
        if [ -n "$lock_pid" ] && kill -0 "$lock_pid" 2>/dev/null; then
            log_error "Another audit process is running (PID $lock_pid). Aborting."
            exit 1
        fi
        log_info "Stale lock file found (PID $lock_pid). Cleaning up."
        rm -f "$LOCK_FILE"
    fi
    echo $$ > "$LOCK_FILE"
    trap 'rm -f "$LOCK_FILE"' EXIT
}

# ── Port listening check helper ──────────────────────────────────────────────

is_port_active() {
    local target_port="$1"
    # 1. Check if the port is in ss -tulnp
    if ss -tulnp 2>/dev/null | grep -q -E ":${target_port}[[:space:]]"; then
        return 0
    fi
    # 2. Check if the port is mapped in running docker containers
    if docker ps --format "{{.Ports}}" | grep -q -E "(^|[^0-9])${target_port}->"; then
        return 0
    fi
    return 1
}

# ── Pre-flight: Port 9445 availability ───────────────────────────────────────

check_port_8001() {
    # Port 9445 SHOULD be listening (homelable-backend port-mapped on host)
    if ! ss -tulnp 2>/dev/null | grep -q ':9445[[:space:]]'; then
        log_error "Port 9445 is not listening — homelable-backend is not port-mapped. Cannot proceed. Aborting."
        exit 1
    fi
    # Parse the service key if present
    local service_key=""
    if [ -f "/srv/configs/docker_compose/homelabel/.env" ]; then
        service_key=$(grep -E "^MCP_SERVICE_KEY=" "/srv/configs/docker_compose/homelabel/.env" | cut -d'=' -f2-)
    fi
    # Verify the backend endpoint is actually responding via HTTP
    local http_code
    http_code=$(curl -s -H "X-MCP-Service-Key: $service_key" -o /dev/null -w '%{http_code}' --max-time 5 "http://localhost:9445/api/v1/health" 2>/dev/null) || http_code="000"
    # 000 = connection failure = server unreachable
    if [ "$http_code" = "000" ]; then
        log_error "Backend endpoint http://localhost:9445/api/v1/health unresponsive on port 9445. May be container crash or network issue. Aborting."
        exit 1
    fi
    log_info "Port 9445 confirmed active for homelable-backend (HTTP $http_code)."
}

# ── Pre-flight: Source file existence ────────────────────────────────────────

check_sources() {
    if [ ! -f "$ALIAS_FILE" ]; then
        log_error "Alias file $ALIAS_FILE not found. Cannot proceed. Aborting."
        exit 1
    fi
    if [ ! -f "$INFRA_FILE" ]; then
        log_error "Infra doc $INFRA_FILE not found. Cannot proceed. Aborting."
        exit 1
    fi
    if [ ! -f "$HOMEPAGE_FILE" ]; then
        log_error "Homepage config $HOMEPAGE_FILE not found. Cannot proceed. Aborting."
        exit 1
    fi
}

# ── Source of Truth: Infra.md ────────────────────────────────────────────────

get_infra_docs() {
    # Extract container/service entries from homelab_Infra.md
    # Support both 4-column and 5-column structures dynamically
    local current_section=""
    while IFS= read -r line || [ -n "$line" ]; do
        # Detect section headers
        if [[ "$line" =~ ^##[[:space:]]+(.+)$ ]]; then
            current_section="${BASH_REMATCH[1]}"
        fi
        
        # Check if line is a markdown table row (must start with | and contain a bold name)
        if [[ "$line" =~ ^\|[[:space:]]*\*\*([a-zA-Z0-9_-]+)\*\*[[:space:]]*\| ]]; then
            # Count the pipes to deduce the number of columns
            local pipe_count
            pipe_count=$(echo -n "$line" | tr -cd '|' | wc -c)
            
            if [ "$pipe_count" -eq 5 ]; then
                # Original 4 columns: | Name | Mapped Ports | Access | Desc |
                local name ports access desc
                IFS='|' read -r _blank name ports access desc _blank_end <<< "$line"
                # Clean up whitespaces & bold marks
                name=$(echo "$name" | tr -d '*' | xargs)
                ports=$(echo "$ports" | xargs)
                access=$(echo "$access" | xargs)
                desc=$(echo "$desc" | xargs)
                # Output: name|ports|section|desc|proxy|access
                printf '%s|%s|%s|%s|%s|%s\n' "$name" "$ports" "$current_section" "$desc" "none" "$access"
            elif [ "$pipe_count" -eq 6 ]; then
                # Restructured 5 columns: | Name | Mapped Ports | Access | Proxy | Desc |
                local name ports access proxy desc
                IFS='|' read -r _blank name ports access proxy desc _blank_end <<< "$line"
                name=$(echo "$name" | tr -d '*' | xargs)
                ports=$(echo "$ports" | xargs)
                access=$(echo "$access" | xargs)
                proxy=$(echo "$proxy" | xargs)
                desc=$(echo "$desc" | xargs)
                # Output: name|ports|section|desc|proxy|access
                printf '%s|%s|%s|%s|%s|%s\n' "$name" "$ports" "$current_section" "$desc" "$proxy" "$access"
            fi
        fi
    done < "$INFRA_FILE"
}

# ── Source of Truth: Live Docker ─────────────────────────────────────────────

get_live_docker() {
    # Use _docker-table alias logic inline
    if ! docker info > /dev/null 2>&1; then
        log_error "Docker daemon is not running. Aborting."
        exit 1
    fi
    docker ps --format "{{.Names}}|{{.Status}}|{{.Ports}}" | while IFS='|' read -r name status ports; do
        cleaned_ports=""
        if [ -n "$ports" ]; then
            IFS=',' read -r -a port_array <<< "$ports"
            for p in "${port_array[@]}"; do
                p=$(echo "$p" | xargs --no-run-if-empty)
                # Strip to the right of -> (e.g., "0.0.0.0:80->80/tcp")
                host_port="${p##*->}"
                # Strip protocol suffix (tcp/udp) for dedup
                host_port="${host_port%%/*}"
                [[ "$host_port" == */tcp ]] && host_port="${host_port%/tcp}"
                [[ "$host_port" == */udp ]] && host_port="${host_port%/udp}"
                if [[ -n "$host_port" ]]; then
                    local found=false
                    local existing
                    for existing in $cleaned_ports; do
                        [ "$existing" = "$host_port" ] && found=true
                    done
                    $found || cleaned_ports="${cleaned_ports:+$cleaned_ports, }$host_port"
                fi
            done
        fi
        if [ -z "$cleaned_ports" ]; then
            cleaned_ports="internal"
        fi
        printf '%s|%s|%s\n' "$name" "$status" "$cleaned_ports"
    done
}

# ── Source of Truth: Homelable Backend Nodes ─────────────────────────────────

get_mcp_nodes() {
    # Parse the service key if present
    local service_key=""
    if [ -f "/srv/configs/docker_compose/homelabel/.env" ]; then
        service_key=$(grep -E "^MCP_SERVICE_KEY=" "/srv/configs/docker_compose/homelabel/.env" | cut -d'=' -f2-)
    fi

    # Fetch nodes from the backend REST API
    local payload
    payload=$(curl -s -H "X-MCP-Service-Key: $service_key" --max-time 10 "${MCP_ENDPOINT}/nodes" 2>/dev/null)
    if [ -z "$payload" ]; then
        log_error "Homelable Backend returned empty response. Aborting."
        exit 1
    fi
    # Parse and output nodes: label|type|ip|status
    echo "$payload" | jq -r '.[]? | "\(.label // .name // "unknown")|\(.type // "node")|\(.ip // "n/a")|\(.status // "unknown")"' 2>/dev/null
}

# ── Source of Truth: Nginx Proxies (Stale-Filtering Enabled) ─────────────────

get_nginx_proxies() {
    local conf_dir="/app/nginxproxy/data/nginx/proxy_host"
    if [ ! -d "$conf_dir" ]; then
        return 0
    fi
    
    # Format: PORT|DOMAINS
    grep -E "set .port|server_name" "$conf_dir"/*.conf 2>/dev/null \
      | sed 's/^[ \t]*//; s/.*conf://' \
      | paste - - \
      | sed 's/set \$port //; s/server_name //; s/;//g' \
      | awk '{$1=$1; print}' \
      | sort -n \
      | while read -r port domains; do
          # STALE CONFIG ELIMINATION: Only report proxies if the mapped port is actively listening
          if is_port_active "$port"; then
              printf '%s|%s\n' "$port" "$domains"
          fi
      done
}

# ── Source of Truth: Homepage Config ─────────────────────────────────────────

get_homepage_services() {
    # Reads services.yaml, stripping carriage returns, and outputs simple mappings: key_name|href|category
    local current_cat=""
    local service_name=""
    local href=""
    while IFS= read -r raw_line || [ -n "$raw_line" ]; do
        local line
        line=$(echo -n "$raw_line" | tr -d '\r')
        
        # Detect category (e.g., "- Devices & Network:" or "- Arr:")
        if [[ "$line" =~ ^-[[:space:]]+([^:]+):$ ]]; then
            # If we had an unprinted service, print it before changing categories
            if [ -n "$service_name" ]; then
                printf '%s|%s|%s\n' "$service_name" "$href" "$current_cat"
                service_name=""
                href=""
            fi
            current_cat="${BASH_REMATCH[1]}"
        # Detect service element (e.g., "  - Proxmox:")
        elif [[ "$line" =~ ^[[:space:]]+-[[:space:]]+([^:]+):$ ]]; then
            if [ -n "$service_name" ]; then
                printf '%s|%s|%s\n' "$service_name" "$href" "$current_cat"
            fi
            service_name="${BASH_REMATCH[1]}"
            href="none"
        # Detect href (e.g., "      href: \"http://10.0.0.142:8006/\"")
        elif [[ "$line" =~ href:[[:space:]]*\"([^\"]+)\" || "$line" =~ href:[[:space:]]*(https?://[^\s]+) ]]; then
            local val="${BASH_REMATCH[1]}"
            val="${val%\"}" # Remove trailing quotes
            val="${val#\"}" # Remove leading quotes
            href="$val"
        fi
    done < "$HOMEPAGE_FILE"
    # Print the last service
    if [ -n "$service_name" ]; then
        printf '%s|%s|%s\n' "$service_name" "$href" "$current_cat"
    fi
}

# ── Source of Truth: Proxmox VMs / LXCs ──────────────────────────────────────

get_infra_proxmox_nodes() {
    # Extract Proxmox VM/LXC entries from homelab_Infra.md
    # Format: | ID  | Type | Hostname        | IP         | Role                            |
    while IFS= read -r line || [ -n "$line" ]; do
        if [[ "$line" =~ ^\|[[:space:]]*([0-9_-]+|-)[[:space:]]*\|[[:space:]]*(LXC|VM)[[:space:]]*\|[[:space:]]*\*\*([a-zA-Z0-9_-]+)\*\*[[:space:]]*\|[[:space:]]*([0-9.]+)[[:space:]]*\| ]]; then
            local type="${BASH_REMATCH[2]}"
            local hostname="${BASH_REMATCH[3]}"
            local ip="${BASH_REMATCH[4]}"
            printf '%s|%s|%s\n' "$hostname" "$type" "$ip"
        fi
    done < "$INFRA_FILE"
}

# ── 3-Way Reconciliation Engine ──────────────────────────────────────────────

reconcile() {
    local infra_count docker_count mcp_count proxy_count hp_count
    infra_count=$(get_infra_docs | wc -l)
    docker_count=$(get_live_docker | wc -l)
    mcp_count=$(get_mcp_nodes | wc -l)
    proxy_count=$(get_nginx_proxies | wc -l)
    hp_count=$(get_homepage_services | wc -l)
    
    log_info "Infra.md: $infra_count | Live Docker: $docker_count | MCP Nodes: $mcp_count | Proxies (Active): $proxy_count | Homepage Dashboard Cards: $hp_count"
    
    local diff_report=""
    diff_report+="## Homelab Infrastructure Reconciliation Report\n"
    diff_report+="Generated: $(date '+%Y-%m-%d %H:%M:%S')\n\n"
    
    # ── Comparison 1: Documentation vs Live Docker Drift ──
    diff_report+="### 1. Documentation vs. Live Docker Drift\n\n"
    
    local doc_names=()
    while IFS='|' read -r name _ports _section _desc _proxy _access; do
        # Only compare Docker Services section
        if [[ "$_section" == "Docker services" ]]; then
            doc_names+=("$name")
        fi
    done < <(get_infra_docs)
    
    local live_names=()
    while IFS='|' read -r name _status _ports; do
        live_names+=("$name")
    done < <(get_live_docker)
    
    # Missing in Docker
    local missing=0
    for doc in "${doc_names[@]}"; do
        local found=false
        for live in "${live_names[@]}"; do
            [ "$doc" = "$live" ] && found=true && break
        done
        # Exceptions
        if [ "$doc" = "dev" ] || [ "$doc" = "calibre" ]; then
            found=true
        fi
        $found || {
            diff_report+="  ✗ **${doc}** — listed in Infra.md but NOT running in Docker\n"
            ((missing++)) || true
        }
    done
    [ $missing -eq 0 ] && diff_report+="  ✅ All documented container services are running\n"
    
    # Untracked in Documentation
    local untracked=0
    for live in "${live_names[@]}"; do
        local found=false
        for doc in "${doc_names[@]}"; do
            [ "$live" = "$doc" ] && found=true && break
        done
        # Map group names or sub-services
        if [[ "$live" == "paperless-webserver-1" && " ${doc_names[*]} " == *" paperless-ngx "* ]]; then found=true; fi
        if [[ "$live" == "paperless-broker-1" && " ${doc_names[*]} " == *" paperless-broker "* ]]; then found=true; fi
        if [[ "$live" == "paperless-db-1" && " ${doc_names[*]} " == *" paperless-db "* ]]; then found=true; fi
        if [[ "$live" == "slopsmith-web" && " ${doc_names[*]} " == *" slopsmith-web "* ]]; then found=true; fi
        if [[ "$live" == "musicbrainz_picard" && " ${doc_names[*]} " == *" musicbrainz_picard "* ]]; then found=true; fi
        
        $found || {
            local status=$(get_live_docker | grep "^${live}|" | head -1 | cut -d'|' -f2)
            local ports=$(get_live_docker | grep "^${live}|" | head -1 | cut -d'|' -f3)
            diff_report+="  ⚠ **${live}** — running (Status: ${status}, Ports: ${ports}) but NOT in Infra.md\n"
            ((untracked++)) || true
        }
    done
    [ $untracked -eq 0 ] && diff_report+="  ✅ No untracked containers running\n"
    
    # Unhealthy Containers
    local unhealthy=0
    while IFS='|' read -r name status _ports; do
        if [[ ! "$status" =~ "(healthy)" && "$status" =~ "Up" ]]; then
            diff_report+="  ⚠ **${name}** — Up but NOT marked healthy (${status})\n"
            ((unhealthy++)) || true
        fi
    done < <(get_live_docker)
    [ $unhealthy -eq 0 ] && diff_report+="  ✅ All active containers are running healthy\n"
    
    # ── Comparison 2: Nginx Proxy Manager Live Mappings vs Doc ──
    diff_report+="\n### 2. Live Nginx Proxy Mappings vs. Documentation\n\n"
    
    local proxy_drift=0
    while IFS='|' read -r port domains; do
        # Cross reference the port against documented services in Infra.md
        local doc_name="unknown"
        local doc_proxy="none"
        while IFS='|' read -r name d_ports _section _desc d_proxy _access; do
            # Check if port matches any documented port
            if [[ " $d_ports " == *"$port"* ]]; then
                doc_name="$name"
                doc_proxy="$d_proxy"
                break
            fi
        done < <(get_infra_docs)
        
        if [ "$doc_name" != "unknown" ]; then
            # Clean domains to simplify matching
            local first_domain
            first_domain=$(echo "$domains" | awk '{print $1}')
            if [ "$doc_proxy" = "none" ] || [ "$doc_proxy" = "-" ]; then
                diff_report+="  ⚠ Port **$port** (**$doc_name**) has proxy domains **($domains)** but has NO proxy domain documented in Infra.md\n"
                ((proxy_drift++)) || true
            elif [[ "$doc_proxy" != *"$first_domain"* ]]; then
                diff_report+="  ⚠ Port **$port** (**$doc_name**) proxy drift! Doc says: \`$doc_proxy\`, Live proxy is: \`$domains\`\n"
                ((proxy_drift++)) || true
            fi
        fi
    done < <(get_nginx_proxies)
    [ $proxy_drift -eq 0 ] && diff_report+="  ✅ All active proxy definitions align with documentation proxy routes\n"
    
    # ── Comparison 3: Live Docker vs MCP Canvas Nodes ──
    diff_report+="\n### 3. Live Docker vs. Homelable Canvas Drift\n\n"
    
    local canvas_drift=0
    # Check if active containers exist on canvas
    while IFS='|' read -r name _status _ports; do
        if [[ "$name" == *"postgres"* || "$name" == *"redis"* || "$name" == *"db"* || "$name" == *"broker"* ]]; then
            continue
        fi
        local found=false
        while IFS='|' read -r label type ip status; do
            # Case insensitive comparison
            local clean_label
            clean_label=$(echo "$label" | tr '[:upper:]' '[:lower:]' | tr ' _-' '    ')
            local clean_name
            clean_name=$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr ' _-' '    ')
            # Custom mappings for neko and hugo public/private
            if [[ "$clean_name" == "docs-public" && "$clean_label" == *"hugo"* && "$clean_label" == *"public"* ]]; then found=true; fi
            if [[ "$clean_name" == "docs-private" && "$clean_label" == *"hugo"* && "$clean_label" == *"pivate"* ]]; then found=true; fi
            if [[ "$clean_name" == "guacamole" && "$clean_label" == *"quacamole"* ]]; then found=true; fi
            
            if [[ "$clean_label" == *"$clean_name"* || "$clean_name" == *"$clean_label"* ]]; then
                found=true
                break
            fi
        done < <(get_mcp_nodes)
        
        $found || {
            diff_report+="  ⚠ **${name}** — container is running, but NOT mapped on the Homelable canvas topology\n"
            ((canvas_drift++)) || true
        }
    done < <(get_live_docker)
    [ $canvas_drift -eq 0 ] && diff_report+="  ✅ All primary running services are mapped on the network canvas\n"

    # ── Comparison 4: Homepage Configuration Audit ──
    diff_report+="\n### 4. Homepage Dashboard Audit (services.yaml)\n\n"
    
    local hp_drift=0
    local hp_services=()
    while IFS='|' read -r s_name s_href s_cat; do
        hp_services+=("$s_name|$s_href|$s_cat")
    done < <(get_homepage_services)

    # Cross reference living proxied ports vs Homepage links
    while IFS='|' read -r port domains; do
        # Check if any alias in domains string is a substring of any card href
        local found=false
        local alias_item
        for alias_item in $domains; do
            alias_item="${alias_item%;}" # strip semicolon
            
            for card in "${hp_services[@]}"; do
                IFS='|' read -r c_name c_href c_cat <<< "$card"
                
                # Case insensitive comparison
                local clean_alias
                clean_alias=$(echo "$alias_item" | tr '[:upper:]' '[:lower:]')
                local clean_href
                clean_href=$(echo "$c_href" | tr '[:upper:]' '[:lower:]')
                local clean_name
                clean_name=$(echo "$c_name" | tr '[:upper:]' '[:lower:]')
                
                if [[ "$clean_href" == *"$clean_alias"* || "$clean_name" == *"$clean_alias"* ]]; then
                    found=true
                    break 2
                fi
            done
        done
        
        # Proxmox remains as is pointing directly to its IP, ignore in mapping drift
        if [[ "$domains" == *"proxmox"* ]]; then
            found=true
        fi
        
        $found || {
            # Skip internal system components
            local first_domain
            first_domain=$(echo "$domains" | awk '{print $1}')
            if [[ "$first_domain" != "nginx" && "$first_domain" != "homelable" && "$first_domain" != "openai" && "$first_domain" != "private" ]]; then
                # Classify the service correctly
                local category="Docker Containers"
                if [[ "$port" == "8006" || "$port" == "8010" ]]; then
                    category="Physical Devices & Networking related"
                elif [[ "$port" == "32015" || "$port" == "30025" || "$port" == "30027" || "$port" == "30014" || "$port" == "30045" || "$port" == "30046" || "$port" == "30050" ]]; then
                    category="Truenas Containers"
                fi
                
                diff_report+="  ⚠ **$first_domain** (Port $port) — active proxy domain is missing from Homepage dashboard! Recommend adding under **$category**.\n"
                ((hp_drift++)) || true
            fi
        }
    done < <(get_nginx_proxies)
    [ $hp_drift -eq 0 ] && diff_report+="  ✅ All active proxied domain targets are mapped on the Homepage dashboard\n"
    
    # ── Comparison 5: Proxmox Virtualization Node Live Audit (LXC / VMs) ──
    diff_report+="\n### 5. Proxmox Virtualization Drift (LXC / VMs)\n\n"
    
    local proxmox_drift=0
    local doc_proxmox=()
    while IFS='|' read -r h_name h_type h_ip; do
        proxmox_proxmox_item=$(echo "$h_name" | tr '[:upper:]' '[:lower:]')
        doc_proxmox+=("$proxmox_proxmox_item")
    done < <(get_infra_proxmox_nodes)

    # Fetch live running LXCs/VMs from Proxmox VE API using dynamically loaded homepage token
    local pve_token=""
    if [ -f "/srv/configs/docker_compose/homepage/.env" ]; then
        pve_token=$(grep -E "^HOMEPAGE_VAR_proxmox_password=" "/srv/configs/docker_compose/homepage/.env" | cut -d'=' -f2- | tr -d '\r')
        # Strip leading/trailing double quotes if present
        pve_token="${pve_token%\"}"
        pve_token="${pve_token#\"}"
    fi

    if [ -n "$pve_token" ]; then
        # Query Proxmox API directly (SSL check bypassed with -k)
        local pve_resources
        pve_resources=$(curl -k -s -H "Authorization: PVEAPIToken=root@pam!dash=$pve_token" "https://10.0.0.142:8006/api2/json/cluster/resources?type=vm" 2>/dev/null) || pve_resources=""
        
        if [ -n "$pve_resources" ]; then
            while read -r pve_node; do
                local label status type
                label=$(echo "$pve_node" | cut -d'|' -f1)
                type=$(echo "$pve_node" | cut -d'|' -f2) # qemu (VM) or lxc
                status=$(echo "$pve_node" | cut -d'|' -f3)

                # Only check active/running nodes
                if [ "$status" = "running" ] && [ "$label" != "docker" ]; then
                    local clean_label
                    clean_label=$(echo "$label" | tr '[:upper:]' '[:lower:]' | tr ' _-' '    ')
                    local found=false
                    for doc_node in "${doc_proxmox[@]}"; do
                        if [[ "$clean_label" == *"$doc_node"* || "$doc_node" == *"$clean_label"* ]]; then
                            found=true
                            break
                        fi
                    done
                    
                    $found || {
                        local friendly_type="VM"
                        [ "$type" = "lxc" ] && friendly_type="LXC"
                        diff_report+="  ⚠ **${label}** — active Proxmox **${friendly_type}** is running, but NOT documented under Proxmox Nodes in Infra.md\n"
                        ((proxmox_drift++)) || true
                    }
                fi
            done < <(echo "$pve_resources" | jq -r '.data[]? | "\(.name)|\(.type)|\(.status)"' 2>/dev/null)
        else
            diff_report+="  ⚠ Unable to query Proxmox VE API (connection failure). Skipping live VM/LXC verification.\n"
            ((proxmox_drift++)) || true
        fi
    else
        diff_report+="  ⚠ Proxmox token missing from homepage/.env. Skipping live VM/LXC verification.\n"
        ((proxmox_drift++)) || true
    fi
    [ $proxmox_drift -eq 0 ] && diff_report+="  ✅ All active Proxmox virtualization nodes are documented\n"

    # ── Comparison 6: TrueNAS SCALE Node Services Live Audit ──
    diff_report+="\n### 6. TrueNAS SCALE Node Services Verification\n\n"
    
    local truenas_drift=0
    # Audit each documented TrueNAS service by performing active port checks directly on truenas (10.0.0.2)
    while IFS='|' read -r name d_ports section desc proxy access; do
        if [[ "$section" == "Truenas Services" ]]; then
            # Verify port is listening over /dev/tcp network socket
            if timeout 1 bash -c "cat < /dev/null > /dev/tcp/10.0.0.2/${d_ports}" 2>/dev/null; then
                # Port is active
                true
            else
                diff_report+="  ✗ **${name}** — documented on TrueNAS port **${d_ports}** but service is NOT listening (down/offline)\n"
                ((truenas_drift++)) || true
            fi
        fi
    done < <(get_infra_docs)
    [ $truenas_drift -eq 0 ] && diff_report+="  ✅ All documented TrueNAS Services are actively running on port 10.0.0.2\n"

    cppt_output=$(echo -e "$diff_report")
    echo "$cppt_output"
}

# ── Main Execution Pipeline ──────────────────────────────────────────────────

main() {
    log_info "═══════════════════════════════════════════════════════"
    log_info "Starting Homelab Infrastructure Reconciliation Audit"
    log_info "═══════════════════════════════════════════════════════"
    
    acquire_lock
    check_port_8001
    check_sources
    log_info "All pre-flight checks passed."
    
    if $DRY_RUN; then
        log_info "DRY RUN — gathering sources without full reconciliation"
        log_info "--- Infra.md entries ---"
        get_infra_docs | while IFS='|' read -r name ports section desc proxy access; do
            echo "  $name (section: $section, ports: $ports, proxy: $proxy)"
        done
        log_info "--- Live Docker containers ---"
        get_live_docker | while IFS='|' read -r name status ports; do
            echo "  $name | $status | $ports"
        done
        log_info "--- Homelable MCP check ---"
        local mcp_result
        mcp_result=$(curl -s --max-time 5 "${MCP_ENDPOINT}" 2>/dev/null || echo "unreachable")
        if [ "$mcp_result" = "unreachable" ]; then
            log_info "  ✗ MCP unreachable"
        else
            log_info "  ✓ MCP reachable (first 100 chars: ${mcp_result:0:100})"
        fi
        return 0
    fi
    
    log_info "Fetching live states..."
    get_infra_docs > /dev/null
    get_live_docker > /dev/null
    get_mcp_nodes > /dev/null
    log_info "All sources fetched."
    
    log_info "Running reconciliation..."
    reconcile
}

main "$@"
