#!/bin/bash

# --- cflat (c♭) ---
# Flattens C/C++ projects into a single text file.
# https://git.alidavid.hu/david/cflat

VERSION="1.0.0"
SCRIPT_NAME=$(basename "$0")

# 1. HELP FUNCTION
function show_help {
    echo "cflat (c♭) v$VERSION"
    echo "Flattens C/C++ projects into a single text file."
    echo "https://git.alidavid.hu/david/cflat"
    echo ""
    echo "Usage: ./$SCRIPT_NAME [DIRECTORY] [-e PATTERN]..."
    echo ""
    echo "Options:"
    echo "  -e, --exclude   Exclude exact path relative to the target directory."
    echo "                  'aaa.a'   -> Excludes ./aaa.a   (Target root only)"
    echo "                  'src/lib' -> Excludes ./src/lib (and its contents)"
    echo "                  '*.txt'   -> Excludes ./*.txt   (Target root only)"
    echo "                  '*/*.txt' -> Excludes ./*/*.txt (Recursive)"
    echo "  -h, --help, -?  Show this message"
    exit 0
}

# 2. ARGUMENT PARSING
TARGET_DIR="."
EXCLUDE_ARGS=()

while [[ $# -gt 0 ]]; do
    case "$1" in
        -h|--help|-\?) show_help ;;
        -e|--exclude)
            if [[ -n "$2" && "$2" != -* ]]; then
                # Clean trailing slash from pattern to match find output safely
                CLEAN_PAT="${2%/}"
                EXCLUDE_ARGS+=("$CLEAN_PAT")
                shift 2
            else
                echo "Error: --exclude requires an argument." >&2; exit 1
            fi
            ;;
        -*) echo "Error: Unknown option $1" >&2; exit 1 ;;
        *) TARGET_DIR="$1"; shift ;;
    esac
done

# Clean target directory (remove trailing slash)
TARGET_DIR=${TARGET_DIR%/}

# 3. BUILD FIND COMMAND
# We anchor every exclusion to the TARGET_DIR.
# This ensures that exclusions are strict (e.g., 'aaa.a' only matches the root file).

# Default ignores (Hidden files, obj, bin, build, and our own output)
BASE_IGNORES=(
    -path '*/.*' -o
    -path '*/obj' -o
    -path '*/bin' -o
    -path '*/build' -o
    -name "cflat-*.txt" -o
    -name "$SCRIPT_NAME"
)

# Build User Excludes
USER_PRUNE_ARGS=()
if [[ ${#EXCLUDE_ARGS[@]} -gt 0 ]]; then
    for pattern in "${EXCLUDE_ARGS[@]}"; do
        # Construct the strict path match anchored to TARGET_DIR
        # e.g., if target is "." and pattern is "file", we match "./file"
        MATCH_PATH="$TARGET_DIR/$pattern"
        
        USER_PRUNE_ARGS+=("-path" "$MATCH_PATH" "-o")
    done
fi

# Combine logic: ( UserExcludes OR BaseIgnores ) -prune
FINAL_PRUNE_ARGS=("(" "${USER_PRUNE_ARGS[@]}" "${BASE_IGNORES[@]}" ")" "-prune")

# 4. CONFIGURATION
TIMESTAMP=$(date +"%Y-%m-%dT%H-%M-%S")
OUTPUT="cflat-export-$TIMESTAMP.txt"
MAX_SIZE_KB=100
HAS_CLANG=$(command -v clang-format)

# 5. HEADER
echo "Generating export for: $TARGET_DIR"
echo "C-FLAT EXPORT" > "$OUTPUT"
echo "Generated on: $(date)" >> "$OUTPUT"
echo "----------------------------------------" >> "$OUTPUT"

# 6. STATISTICS
echo "PROJECT STATISTICS:" >> "$OUTPUT"
find "$TARGET_DIR" "${FINAL_PRUNE_ARGS[@]}" -o -type f \( -name "*.cpp" -o -name "*.hpp" -o -name "*.c" -o -name "*.h" \) -print0 | xargs -0 -r wc -l | tail -n 1 >> "$OUTPUT"

# 7. KEY DEFINITIONS
echo -e "\nKEY DEFINITIONS FOUND:" >> "$OUTPUT"
find "$TARGET_DIR" "${FINAL_PRUNE_ARGS[@]}" -o -type f -exec grep -nE "class [A-Za-z0-9_]+|struct [A-Za-z0-9_]+" {} + >> "$OUTPUT"

# 8. PROJECT STRUCTURE
echo -e "\nPROJECT STRUCTURE:" >> "$OUTPUT"
# Print all non-pruned paths for the tree visualization
find "$TARGET_DIR" "${FINAL_PRUNE_ARGS[@]}" -o -print | sort | sed -e "s;[^/]*/;|____;g;s;____|; |;g" >> "$OUTPUT"

echo -e "\n--- FILE CONTENTS ---\n" >> "$OUTPUT"

# 9. CONTENT EXPORT
find "$TARGET_DIR" "${FINAL_PRUNE_ARGS[@]}" -o -type f -print | while read -r file; do
    
    if [[ "$file" =~ \.(cpp|hpp|h|c|cc|cxx)$ ]]; then
        echo "--- START OF SOURCE FILE: $file ---" >> "$OUTPUT"
        if [ -n "$HAS_CLANG" ]; then
            clang-format --style=LLVM "$file" >> "$OUTPUT"
        else
            cat "$file" >> "$OUTPUT"
        fi
        echo -e "\n--- END OF SOURCE FILE: $file ---\n" >> "$OUTPUT"
        
    elif [[ "$file" == *"Makefile"* ]] || [[ "$file" =~ \.(txt|py|sh|md|cmake)$ ]]; then
        echo "--- START OF CONFIG/SCRIPT: $file ---" >> "$OUTPUT"
        cat "$file" >> "$OUTPUT"
        echo -e "\n--- END OF CONFIG/SCRIPT: $file ---\n" >> "$OUTPUT"
        
    elif grep -qI . "$file"; then
        FILE_SIZE=$(du -k "$file" | cut -f1)
        if [ "$FILE_SIZE" -lt "$MAX_SIZE_KB" ]; then
            echo "--- START OF ASSET FILE: $file ---" >> "$OUTPUT"
            cat "$file" >> "$OUTPUT"
            echo -e "\n--- END OF ASSET FILE: $file ---\n" >> "$OUTPUT"
        fi
    fi
done

# 10. AUTO-GITIGNORE
GITIGNORE="$TARGET_DIR/.gitignore"
if [ -f "$GITIGNORE" ]; then
    if ! grep -qxF "$SCRIPT_NAME" "$GITIGNORE"; then
        echo -e "\n# C-Flat ignores\n$SCRIPT_NAME" >> "$GITIGNORE"
    fi
    if ! grep -qF "cflat-*.txt" "$GITIGNORE"; then
        echo "cflat-*.txt" >> "$GITIGNORE"
    fi
fi

echo "Done: Output saved to $OUTPUT"