#!/usr/bin/env bash
# test-domain-unreal.sh - Validate Unreal Engine security extractors
# Part of the Comprehensive Vision UAT

set -euo pipefail

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
UAT_DIR="$(dirname "$SCRIPT_DIR")"
APHORIA_DIR="$(dirname "$UAT_DIR")"
STEMEDB_DIR="$(dirname "$(dirname "$APHORIA_DIR")")"

# Build Aphoria if needed
APHORIA_BIN="${STEMEDB_DIR}/target/release/aphoria"
if [[ ! -f "$APHORIA_BIN" ]]; then
    echo "Building Aphoria..."
    cargo build --release --package aphoria --manifest-path "${STEMEDB_DIR}/Cargo.toml"
fi

# Test fixtures directory
FIXTURES_DIR="${UAT_DIR}/fixtures/unreal"
mkdir -p "$FIXTURES_DIR"

PASSED=0
FAILED=0
TOTAL=0

test_case() {
    local id="$1"
    local description="$2"
    TOTAL=$((TOTAL + 1))
    echo -e "\n${YELLOW}[$id]${NC} $description"
}

pass() {
    PASSED=$((PASSED + 1))
    echo -e "  ${GREEN}✓ PASS${NC}"
}

fail() {
    local reason="$1"
    FAILED=$((FAILED + 1))
    echo -e "  ${RED}✗ FAIL: $reason${NC}"
}

# Create test fixtures for Unreal Engine
create_fixtures() {
    echo "Creating Unreal Engine test fixtures..."

    # Create a minimal project structure for Unreal
    mkdir -p "${FIXTURES_DIR}/Source/MyGame"

    # Vulnerable Unreal C++ header
    cat > "${FIXTURES_DIR}/Source/MyGame/GameActor.h" << 'EOF'
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GameActor.generated.h"

UCLASS()
class MYGAME_API AGameActor : public AActor
{
    GENERATED_BODY()

public:
    // BAD: Exec functions can be called from console by cheaters
    UFUNCTION(Exec)
    void CheatGiveGold();

    UFUNCTION(Exec, Category="Debug")
    void DebugTeleport();

    // BAD: Replicated without condition - bandwidth waste
    UPROPERTY(Replicated)
    int32 PlayerHealth;

    UPROPERTY(Replicated)
    FVector LastPosition;

protected:
    // BAD: Hardcoded asset path - fragile
    void LoadAssets()
    {
        UObject* Sword = LoadObject<UObject>(nullptr, TEXT("/Game/Items/Sword.Sword"));
        UObject* Shield = LoadObject<UObject>(nullptr, TEXT("/Engine/BasicShapes/Cube.Cube"));
    }
};
EOF

    # Clean Unreal C++ header (no issues)
    cat > "${FIXTURES_DIR}/Source/MyGame/CleanActor.h" << 'EOF'
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CleanActor.generated.h"

UCLASS()
class MYGAME_API ACleanActor : public AActor
{
    GENERATED_BODY()

public:
    // GOOD: BlueprintCallable, not Exec
    UFUNCTION(BlueprintCallable)
    void SetHealth(int32 NewHealth);

    // GOOD: Replicated with condition
    UPROPERTY(ReplicatedUsing=OnRep_Health)
    int32 Health;

    UFUNCTION()
    void OnRep_Health();

protected:
    // GOOD: Asset reference via UPROPERTY
    UPROPERTY(EditDefaultsOnly)
    TSoftObjectPtr<UObject> SwordAsset;
};
EOF

    # Create a minimal Cargo.toml so the directory looks like a project
    cat > "${FIXTURES_DIR}/Cargo.toml" << 'EOF'
[package]
name = "unreal-test-project"
version = "0.1.0"
edition = "2021"
EOF
}

# Helper to strip ANSI codes
strip_ansi() {
    sed 's/\x1b\[[0-9;]*m//g'
}

# Test 7.1.1: UFUNCTION(Exec) detected
test_exec_function() {
    test_case "7.1.1" "UFUNCTION(Exec) exposed console command detected"

    local output
    output=$("$APHORIA_BIN" scan "${FIXTURES_DIR}" --format json 2>&1 | strip_ansi || true)

    # Check for claims extracted or conflicts detected (Unreal extractors produce conflicts)
    if echo "$output" | grep -qE 'claims_extracted=[1-9][0-9]*|conflicts.*\[.*exec_function'; then
        pass
    else
        fail "UFUNCTION(Exec) pattern not detected (no claims extracted)"
        echo "  Output: $(echo "$output" | head -20)"
    fi
}

# Test 7.1.2: UPROPERTY(Replicated) without condition
test_unconditional_replication() {
    test_case "7.1.2" "UPROPERTY(Replicated) without condition detected"

    local output
    output=$("$APHORIA_BIN" scan "${FIXTURES_DIR}" --format json 2>&1 | strip_ansi || true)

    # Check for claims extracted (Unreal patterns produce claims)
    if echo "$output" | grep -qE 'claims_extracted=[1-9][0-9]*'; then
        pass
    else
        fail "Unconditional replication not detected (no claims extracted)"
        echo "  Output: $(echo "$output" | head -20)"
    fi
}

# Test 7.1.3: Hardcoded asset path TEXT("/Game/...")
test_hardcoded_asset_path() {
    test_case "7.1.3" "Hardcoded asset path TEXT(\"/Game/...\") detected"

    local output
    output=$("$APHORIA_BIN" scan "${FIXTURES_DIR}" --format json 2>&1 | strip_ansi || true)

    # Check for claims extracted
    if echo "$output" | grep -qE 'claims_extracted=[1-9][0-9]*'; then
        pass
    else
        fail "Hardcoded asset path not detected (no claims extracted)"
        echo "  Output: $(echo "$output" | head -20)"
    fi
}

# Test 7.1.4: Clean Unreal code has no conflicts
test_clean_unreal_code() {
    test_case "7.1.4" "Clean Unreal code produces no false positives"

    # Create a separate clean-only directory
    local clean_dir="${FIXTURES_DIR}/clean-only"
    mkdir -p "${clean_dir}/Source/MyGame"

    cat > "${clean_dir}/Source/MyGame/CleanActor.h" << 'EOF'
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CleanActor.generated.h"

UCLASS()
class MYGAME_API ACleanActor : public AActor
{
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintCallable)
    void SetHealth(int32 NewHealth);

    UPROPERTY(ReplicatedUsing=OnRep_Health)
    int32 Health;

    UFUNCTION()
    void OnRep_Health();

protected:
    UPROPERTY(EditDefaultsOnly)
    TSoftObjectPtr<UObject> SwordAsset;
};
EOF

    cat > "${clean_dir}/Cargo.toml" << 'EOF'
[package]
name = "clean-unreal"
version = "0.1.0"
edition = "2021"
EOF

    local output
    output=$("$APHORIA_BIN" scan "${clean_dir}" --format json 2>&1 | strip_ansi || true)

    # Clean code should have no Unreal-specific conflicts in the JSON output
    # Check for "conflicts": [] indicating no conflicts found
    if echo "$output" | grep -q '"conflicts": \[\]'; then
        pass
    else
        # If there are conflicts, verify they're not Unreal-specific ones
        if echo "$output" | grep -qi 'exec_function\|hardcoded_path\|unconditional_replication'; then
            fail "Clean Unreal code should not produce Unreal-specific conflicts"
            echo "  Output: $(echo "$output" | head -20)"
        else
            pass
        fi
    fi
}

# Run all tests
main() {
    echo "========================================"
    echo "Aphoria Unreal Engine UAT"
    echo "========================================"

    create_fixtures

    echo ""
    echo "Running Unreal Engine security tests..."

    test_exec_function
    test_unconditional_replication
    test_hardcoded_asset_path
    test_clean_unreal_code

    echo ""
    echo "========================================"
    echo "Results: $PASSED/$TOTAL passed, $FAILED failed"
    echo "========================================"

    if [[ $FAILED -gt 0 ]]; then
        exit 1
    fi
}

main "$@"
