#!/bin/bash
# scripts/detect-god-objects.sh
# Detects models with excessive relationships (god objects)
#
# Exit codes:
#   0 = Always passes (warnings only, doesn't fail builds)
#
# Usage: ./scripts/detect-god-objects.sh [threshold]
#   threshold: Number of relationships to trigger warning (default: 8)

set -e

THRESHOLD=${1:-8}

# Known aggregate roots with documented high complexity (won't trigger warnings)
# Format: "ModelName:MaxAllowed:Reason"
KNOWN_AGGREGATES=(
    "Gala:15:Fork pattern - owns forked venue instances, content, and access control"
    "Order:12:Order lifecycle - manages payment, audit, and fulfillment sub-domains"
)

echo "👹 God Object Detection"
echo "======================="
echo "Threshold: $THRESHOLD relationships"
echo ""
echo "Known Aggregate Roots (documented exceptions):"
for AGG in "${KNOWN_AGGREGATES[@]}"; do
    MODEL_NAME=$(echo "$AGG" | cut -d: -f1)
    MAX=$(echo "$AGG" | cut -d: -f2)
    REASON=$(echo "$AGG" | cut -d: -f3)
    echo "  ✓ $MODEL_NAME (≤$MAX): $REASON"
done
echo ""

GOD_OBJECTS=0
TOTAL_MODELS=0

# Analyze each model
for MODEL in $(find app/Domains -name "*.php" -type f); do
    TOTAL_MODELS=$((TOTAL_MODELS + 1))

    # Count relationship methods (suppress errors, default to 0)
    REL_COUNT=$(grep -c "belongsTo\|hasMany\|hasOne\|morphTo\|morphMany\|hasManyThrough\|belongsToMany" "$MODEL" 2>/dev/null || true)
    # Handle empty/non-numeric results
    if [ -z "$REL_COUNT" ] || ! [[ "$REL_COUNT" =~ ^[0-9]+$ ]]; then
        REL_COUNT=0
    fi

    if [ "$REL_COUNT" -ge "$THRESHOLD" ]; then
        MODEL_NAME=$(basename "$MODEL" .php)
        DOMAIN=$(echo "$MODEL" | sed 's|app/Domains/||' | cut -d'/' -f1)

        # Check if this is a known aggregate root
        IS_KNOWN=false
        ALLOWED_MAX=0
        AGGREGATE_REASON=""
        for AGG in "${KNOWN_AGGREGATES[@]}"; do
            AGG_NAME=$(echo "$AGG" | cut -d: -f1)
            if [ "$AGG_NAME" = "$MODEL_NAME" ]; then
                IS_KNOWN=true
                ALLOWED_MAX=$(echo "$AGG" | cut -d: -f2)
                AGGREGATE_REASON=$(echo "$AGG" | cut -d: -f3)
                break
            fi
        done

        # Check if within documented threshold for known aggregates
        if [ "$IS_KNOWN" = true ] && [ "$REL_COUNT" -le "$ALLOWED_MAX" ]; then
            echo "✓ $DOMAIN/$MODEL_NAME has $REL_COUNT relationships (aggregate root)"
            echo "   Documented: $AGGREGATE_REASON"
            echo "   Status: Within expected range (≤$ALLOWED_MAX)"
        elif [ "$IS_KNOWN" = true ]; then
            echo "⚠️  $DOMAIN/$MODEL_NAME has $REL_COUNT relationships (EXCEEDS aggregate threshold!)"
            echo "   Expected: ≤$ALLOWED_MAX"
            echo "   Current: $REL_COUNT (${REL_COUNT} relationships)"
            echo "   Reason: $AGGREGATE_REASON"
            echo "   Action: Review if aggregate has grown beyond intended scope"
            GOD_OBJECTS=$((GOD_OBJECTS + 1))
        else
            echo "⚠️  $DOMAIN/$MODEL_NAME has $REL_COUNT relationships"
            echo "   File: $MODEL"

            # Show relationship methods
            echo "   Relationships:"
            grep -n "function.*\(\)" "$MODEL" 2>/dev/null | \
                grep -B1 "belongsTo\|hasMany\|hasOne\|morphTo\|morphMany" | \
                grep "function" | \
                sed 's/.*function /     - /' | \
                sed 's/().*/()/' || echo "     (could not parse)"

            GOD_OBJECTS=$((GOD_OBJECTS + 1))
        fi

        echo ""
    fi
done

echo "================================"
echo "Summary:"
echo "  Total models: $TOTAL_MODELS"
echo "  God objects: $GOD_OBJECTS (>= $THRESHOLD relationships)"
echo ""

if [ $GOD_OBJECTS -gt 0 ]; then
    echo "⚠️  God objects detected (warning only)"
    echo ""
    echo "Recommendations:"
    echo "  - Consider splitting models with >$THRESHOLD relationships"
    echo "  - Look for aggregate root candidates"
    echo "  - Review for Single Responsibility Principle violations"
    echo ""
    echo "This is informational only - build will pass"
else
    echo "✅ No god objects found"
fi

exit 0  # Always pass (warning only)
