#!/usr/bin/env bash
set -euo pipefail

# ---------------------------------------------------------------------------
# Cross-validation test script for Kotlin ArchiveDecoder
#
# Creates archives with the Rust CLI, decodes with the Kotlin decoder,
# and verifies byte-identical output via SHA-256 comparison.
# ---------------------------------------------------------------------------

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
TMPDIR=""
PASS_COUNT=0
FAIL_COUNT=0
TOTAL_COUNT=0

# Colors (if terminal supports them)
if [ -t 1 ]; then
    GREEN='\033[0;32m'
    RED='\033[0;31m'
    YELLOW='\033[0;33m'
    BOLD='\033[1m'
    NC='\033[0m'
else
    GREEN=''
    RED=''
    YELLOW=''
    BOLD=''
    NC=''
fi

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

cleanup() {
    if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then
        rm -rf "$TMPDIR"
    fi
}
trap cleanup EXIT

pass() {
    local name="$1"
    PASS_COUNT=$((PASS_COUNT + 1))
    TOTAL_COUNT=$((TOTAL_COUNT + 1))
    echo -e "  ${GREEN}PASS${NC}: $name"
}

fail() {
    local name="$1"
    local detail="${2:-}"
    FAIL_COUNT=$((FAIL_COUNT + 1))
    TOTAL_COUNT=$((TOTAL_COUNT + 1))
    echo -e "  ${RED}FAIL${NC}: $name"
    if [ -n "$detail" ]; then
        echo "        $detail"
    fi
}

sha256_of() {
    sha256sum "$1" | awk '{print $1}'
}

verify_file() {
    local original="$1"
    local extracted="$2"
    local label="$3"

    if [ ! -f "$extracted" ]; then
        fail "$label" "Extracted file not found: $extracted"
        return
    fi

    local orig_hash
    local ext_hash
    orig_hash=$(sha256_of "$original")
    ext_hash=$(sha256_of "$extracted")

    if [ "$orig_hash" = "$ext_hash" ]; then
        pass "$label (SHA-256: ${orig_hash:0:16}...)"
    else
        fail "$label" "SHA-256 mismatch: original=$orig_hash extracted=$ext_hash"
    fi
}

# ---------------------------------------------------------------------------
# Prerequisites check
# ---------------------------------------------------------------------------

echo -e "${BOLD}Checking prerequisites...${NC}"

if ! command -v kotlinc &>/dev/null; then
    echo -e "${RED}ERROR${NC}: kotlinc not found."
    echo "  Install Kotlin compiler:"
    echo "    - SDKMAN:  sdk install kotlin"
    echo "    - Homebrew: brew install kotlin"
    echo "    - Snap:    sudo snap install kotlin --classic"
    echo "    - Manual:  https://kotlinlang.org/docs/command-line.html"
    exit 1
fi

if ! command -v java &>/dev/null; then
    echo -e "${RED}ERROR${NC}: java not found."
    echo "  Install Java runtime:"
    echo "    - Ubuntu: sudo apt install default-jdk"
    echo "    - SDKMAN: sdk install java"
    exit 1
fi

if ! command -v cargo &>/dev/null; then
    echo -e "${RED}ERROR${NC}: cargo not found."
    echo "  Install Rust: https://rustup.rs/"
    exit 1
fi

echo "  kotlinc: $(kotlinc -version 2>&1 | head -1)"
echo "  java:    $(java -version 2>&1 | head -1)"
echo "  cargo:   $(cargo --version)"
echo ""

# ---------------------------------------------------------------------------
# Build Rust archiver
# ---------------------------------------------------------------------------

echo -e "${BOLD}Building Rust archiver...${NC}"
(cd "$PROJECT_DIR" && cargo build --release -q)
ARCHIVER="$PROJECT_DIR/target/release/encrypted_archive"
echo "  Built: $ARCHIVER"
echo ""

# ---------------------------------------------------------------------------
# Compile Kotlin decoder
# ---------------------------------------------------------------------------

echo -e "${BOLD}Compiling Kotlin decoder...${NC}"
JAR="$SCRIPT_DIR/ArchiveDecoder.jar"
kotlinc "$SCRIPT_DIR/ArchiveDecoder.kt" -include-runtime -d "$JAR" 2>&1 | tail -5 || true
if [ ! -f "$JAR" ]; then
    echo -e "${RED}ERROR${NC}: Compilation failed. ArchiveDecoder.jar not found."
    exit 1
fi
echo "  Compiled: $JAR"
echo ""

# ---------------------------------------------------------------------------
# Create temp directory
# ---------------------------------------------------------------------------

TMPDIR=$(mktemp -d)
echo -e "${BOLD}Temp directory: $TMPDIR${NC}"
echo ""

# ---------------------------------------------------------------------------
# Test case 1: Single text file
# ---------------------------------------------------------------------------

echo -e "${BOLD}Test 1: Single text file${NC}"

ORIG1="$TMPDIR/hello.txt"
echo -n "Hello, World!" > "$ORIG1"

"$ARCHIVER" pack "$ORIG1" -o "$TMPDIR/test1.archive"
java -jar "$JAR" "$TMPDIR/test1.archive" "$TMPDIR/output1/"

verify_file "$ORIG1" "$TMPDIR/output1/hello.txt" "hello.txt"
echo ""

# ---------------------------------------------------------------------------
# Test case 2: Multiple files with mixed content (text + binary + Cyrillic)
# ---------------------------------------------------------------------------

echo -e "${BOLD}Test 2: Multiple files with mixed content${NC}"

ORIG2_TEXT="$TMPDIR/text.txt"
cat > "$ORIG2_TEXT" << 'TEXTEOF'
This is a test file with multiple lines.
It contains ASCII and Cyrillic characters.
Line 3: testing 1 2 3.
TEXTEOF

ORIG2_BIN="$TMPDIR/binary.bin"
dd if=/dev/urandom bs=1024 count=10 of="$ORIG2_BIN" 2>/dev/null

"$ARCHIVER" pack "$ORIG2_TEXT" "$ORIG2_BIN" -o "$TMPDIR/test2.archive"
java -jar "$JAR" "$TMPDIR/test2.archive" "$TMPDIR/output2/"

verify_file "$ORIG2_TEXT" "$TMPDIR/output2/text.txt" "text.txt (multiline UTF-8)"
verify_file "$ORIG2_BIN" "$TMPDIR/output2/binary.bin" "binary.bin (10 KB random)"
echo ""

# ---------------------------------------------------------------------------
# Test case 3: Already-compressed file (APK-like, no compression)
# ---------------------------------------------------------------------------

echo -e "${BOLD}Test 3: Already-compressed file (no-compress mode)${NC}"

ORIG3="$TMPDIR/fake.dat"
dd if=/dev/urandom bs=512 count=5 of="$ORIG3" 2>/dev/null

# Use --no-compress with the filename pattern to skip compression
"$ARCHIVER" pack "$ORIG3" -o "$TMPDIR/test3.archive" --no-compress "fake.dat"
java -jar "$JAR" "$TMPDIR/test3.archive" "$TMPDIR/output3/"

verify_file "$ORIG3" "$TMPDIR/output3/fake.dat" "fake.dat (no-compress)"
echo ""

# ---------------------------------------------------------------------------
# Test case 4: Empty file
# ---------------------------------------------------------------------------

echo -e "${BOLD}Test 4: Empty file${NC}"

ORIG4="$TMPDIR/empty.txt"
touch "$ORIG4"

"$ARCHIVER" pack "$ORIG4" -o "$TMPDIR/test4.archive"
java -jar "$JAR" "$TMPDIR/test4.archive" "$TMPDIR/output4/"

# Verify output file exists and is empty
if [ -f "$TMPDIR/output4/empty.txt" ]; then
    EMPTY_SIZE=$(wc -c < "$TMPDIR/output4/empty.txt")
    if [ "$EMPTY_SIZE" -eq 0 ]; then
        pass "empty.txt (0 bytes)"
    else
        fail "empty.txt" "Expected 0 bytes, got $EMPTY_SIZE bytes"
    fi
else
    fail "empty.txt" "File not found in output"
fi
echo ""

# ---------------------------------------------------------------------------
# Test case 5: Large file (100 KB)
# ---------------------------------------------------------------------------

echo -e "${BOLD}Test 5: Large file (100 KB)${NC}"

ORIG5="$TMPDIR/large.bin"
dd if=/dev/urandom bs=1024 count=100 of="$ORIG5" 2>/dev/null

"$ARCHIVER" pack "$ORIG5" -o "$TMPDIR/test5.archive"
java -jar "$JAR" "$TMPDIR/test5.archive" "$TMPDIR/output5/"

verify_file "$ORIG5" "$TMPDIR/output5/large.bin" "large.bin (100 KB random)"
echo ""

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------

echo -e "${BOLD}========================================${NC}"
echo -e "${BOLD}Results: $PASS_COUNT passed, $FAIL_COUNT failed out of $TOTAL_COUNT tests${NC}"
echo -e "${BOLD}========================================${NC}"

if [ "$FAIL_COUNT" -gt 0 ]; then
    echo -e "${RED}SOME TESTS FAILED${NC}"
    exit 1
else
    echo -e "${GREEN}ALL TESTS PASSED${NC}"
    exit 0
fi
