#!/usr/bin/env bash
#
# Test suite for swiftlint_generate_filelist.sh
# This script validates that the SwiftLint file list generation works correctly
# in various scenarios including caching, staged/unstaged files, and edge cases.

set -euo pipefail

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

# Test counters
TESTS_RUN=0
TESTS_PASSED=0
TESTS_FAILED=0

# Get script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SWIFTLINT_SCRIPT="$SCRIPT_DIR/swiftlint_generate_filelist.sh"

# Test utilities
print_test_header() {
    echo
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "Test $TESTS_RUN: $1"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}

pass_test() {
    TESTS_PASSED=$((TESTS_PASSED + 1))
    echo -e "${GREEN}✓${NC} $1"
}

fail_test() {
    TESTS_FAILED=$((TESTS_FAILED + 1))
    echo -e "${RED}✗ FAIL:${NC} $1"
    if [[ -n "${2:-}" ]]; then
        echo -e "${YELLOW}  Output:${NC} $2"
    fi
}

run_test() {
    TESTS_RUN=$((TESTS_RUN + 1))
}

cleanup_test_env() {
    # Restore any modified files
    git restore --staged . 2>/dev/null || true
    git restore . 2>/dev/null || true

    # Remove test build folder
    rm -rf "$SCRIPT_DIR/../DerivedData/Build/SwiftLint"
}

# Setup
echo "╔════════════════════════════════════════════════════════╗"
echo "║  SwiftLint File List Generator - Test Suite           ║"
echo "╚════════════════════════════════════════════════════════╝"
echo
echo "Testing script: $SWIFTLINT_SCRIPT"
echo

# Verify script exists
if [[ ! -f "$SWIFTLINT_SCRIPT" ]]; then
    echo -e "${RED}ERROR:${NC} Script not found: $SWIFTLINT_SCRIPT"
    exit 1
fi

# Find test files (must exist in the repository)
TEST_FILE1="Sources/FeatureEditClip/Extend/ClipSuggestionsView.swift"
TEST_FILE2="Sources/FeaturePlayer/Logging.swift"

if [[ ! -f "$TEST_FILE1" ]] || [[ ! -f "$TEST_FILE2" ]]; then
    echo -e "${RED}ERROR:${NC} Test files not found. This test suite requires:"
    echo "  - $TEST_FILE1"
    echo "  - $TEST_FILE2"
    exit 1
fi

# Ensure clean state
cleanup_test_env

# ============================================================================
# TEST 1: Fresh run with no Swift changes
# ============================================================================
run_test
print_test_header "Fresh run with no Swift changes"

OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ -f "DerivedData/Build/SwiftLint/swiftlint_input.xcfilelist" ]]; then
    pass_test "File list created"
else
    fail_test "File list not created"
fi

if [[ -f "DerivedData/Build/SwiftLint/swiftlint_static_output" ]]; then
    pass_test "Static output file created"
else
    fail_test "Static output file not created"
fi

if [[ "$OUTPUT" == *"No changed Swift files found"* ]]; then
    pass_test "Correct message for no changes"
else
    fail_test "Expected 'No changed Swift files found' message" "$OUTPUT"
fi

# ============================================================================
# TEST 2: Cache hit with no changes
# ============================================================================
run_test
print_test_header "Cache hit with no changes"

OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"No changes since last git diff"* ]]; then
    pass_test "Cache hit detected correctly"
else
    fail_test "Should have hit cache" "$OUTPUT"
fi

# ============================================================================
# TEST 3: Detect modified Swift file
# ============================================================================
run_test
print_test_header "Detect modified Swift file"

echo "// Test modification 1" >> "$TEST_FILE1"
OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"Found 1 changed Swift file(s)"* ]]; then
    pass_test "Single modification detected"
else
    fail_test "Should detect 1 file change" "$OUTPUT"
fi

FILELIST=$(cat DerivedData/Build/SwiftLint/swiftlint_input.xcfilelist)
if [[ "$FILELIST" == *"ClipSuggestionsView.swift"* ]]; then
    pass_test "File included in list"
else
    fail_test "File not in list" "$FILELIST"
fi

if [[ "$FILELIST" == *'$(SRCROOT)/'* ]]; then
    pass_test "File path has correct SRCROOT prefix"
else
    fail_test "File path missing SRCROOT prefix" "$FILELIST"
fi

# ============================================================================
# TEST 4: Cache hit with unchanged modification
# ============================================================================
run_test
print_test_header "Cache hit with unchanged modification"

OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"No changes since last git diff"* ]]; then
    pass_test "Cache working with modifications"
else
    fail_test "Should have hit cache" "$OUTPUT"
fi

# ============================================================================
# TEST 5: Additional modification to same file
# ============================================================================
run_test
print_test_header "Additional modification to same file (git diff --raw unchanged)"

echo "// Test modification 2" >> "$TEST_FILE1"
OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"No changes since last git diff"* ]]; then
    pass_test "Cache correctly identifies unchanged diff output"
else
    fail_test "Should hit cache (git diff --raw output unchanged)" "$OUTPUT"
fi

# ============================================================================
# TEST 6: Multiple file changes
# ============================================================================
run_test
print_test_header "Multiple file changes"

echo "// Test modification" >> "$TEST_FILE2"
OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"Found 2 changed Swift file(s)"* ]]; then
    pass_test "Multiple modifications detected"
else
    fail_test "Should detect 2 file changes" "$OUTPUT"
fi

FILELIST=$(cat DerivedData/Build/SwiftLint/swiftlint_input.xcfilelist)
if [[ "$FILELIST" == *"ClipSuggestionsView.swift"* ]] && [[ "$FILELIST" == *"Logging.swift"* ]]; then
    pass_test "Both files included in list"
else
    fail_test "Both files not in list" "$FILELIST"
fi

# ============================================================================
# TEST 7: Cache hit with multiple files
# ============================================================================
run_test
print_test_header "Cache hit with multiple modified files"

OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"No changes since last git diff"* ]]; then
    pass_test "Cache working with multiple files"
else
    fail_test "Should have hit cache" "$OUTPUT"
fi

# ============================================================================
# TEST 8: Detect staged file change
# ============================================================================
run_test
print_test_header "Detect staged file change"

git add "$TEST_FILE1"
OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"Found 2 changed Swift file(s)"* ]]; then
    pass_test "Staged change detected (diff output changed)"
else
    fail_test "Should detect that diff output changed" "$OUTPUT"
fi

# ============================================================================
# TEST 9: Detect file restoration
# ============================================================================
run_test
print_test_header "Detect file restoration"

git restore --staged "$TEST_FILE1"
git restore "$TEST_FILE1"
OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"Found 1 changed Swift file(s)"* ]]; then
    pass_test "File restoration detected"
else
    fail_test "Should detect only 1 file now" "$OUTPUT"
fi

FILELIST=$(cat DerivedData/Build/SwiftLint/swiftlint_input.xcfilelist)
if [[ "$FILELIST" != *"ClipSuggestionsView.swift"* ]]; then
    pass_test "Restored file removed from list"
else
    fail_test "Restored file should not be in list" "$FILELIST"
fi

# ============================================================================
# TEST 10: Complete restoration (back to clean state)
# ============================================================================
run_test
print_test_header "Complete restoration to clean state"

git restore "$TEST_FILE2"
OUTPUT=$("$SWIFTLINT_SCRIPT" 2>&1)

if [[ "$OUTPUT" == *"No changed Swift files found"* ]]; then
    pass_test "All files restored, no changes detected"
else
    fail_test "Should detect no changes after full restoration" "$OUTPUT"
fi

FILELIST=$(cat DerivedData/Build/SwiftLint/swiftlint_input.xcfilelist)
if [[ -z "$FILELIST" || "$FILELIST" =~ ^[[:space:]]*$ ]]; then
    pass_test "File list is empty"
else
    fail_test "File list should be empty" "$FILELIST"
fi

# ============================================================================
# Cleanup
# ============================================================================
echo
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Cleaning up test environment..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
cleanup_test_env
echo "✓ Cleanup complete"

# ============================================================================
# Summary
# ============================================================================
echo
echo "╔════════════════════════════════════════════════════════╗"
echo "║                    TEST SUMMARY                        ║"
echo "╚════════════════════════════════════════════════════════╝"
echo
echo "  Total Tests:  $TESTS_RUN"
echo -e "  ${GREEN}Passed:${NC}      $TESTS_PASSED"
if [[ $TESTS_FAILED -gt 0 ]]; then
    echo -e "  ${RED}Failed:${NC}      $TESTS_FAILED"
else
    echo "  Failed:      $TESTS_FAILED"
fi
echo

if [[ $TESTS_FAILED -eq 0 ]]; then
    echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║              ALL TESTS PASSED! ✓                       ║${NC}"
    echo -e "${GREEN}╚════════════════════════════════════════════════════════╝${NC}"
    exit 0
else
    echo -e "${RED}╔════════════════════════════════════════════════════════╗${NC}"
    echo -e "${RED}║              SOME TESTS FAILED ✗                       ║${NC}"
    echo -e "${RED}╚════════════════════════════════════════════════════════╝${NC}"
    exit 1
fi
