#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#define MAX_PATH_LEN MAX_PATH  // MAX_PATH is defined in windows.h (typically 260)

// Function prototypes
void ProcessDirectory(const char *directory, FILE *outFile);
void ProcessBSPFile(const char *filePath, FILE *outFile);

// Entry point: expects one argument (the directory to scan)
int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <directory>\n", argv[0]);
        return 1;
    }

    // Open the output file for writing (will create/overwrite invalid_BSPs.txt)
    FILE *outFile = fopen("invalid_BSPs.txt", "w");
    if (!outFile) {
        perror("Error opening output file");
        return 1;
    }

    // Begin recursive processing
    ProcessDirectory(argv[1], outFile);

    fclose(outFile);
    printf("Processing complete. Check invalid_BSPs.txt for results.\n");
    return 0;
}

// Recursively processes directories to find .bsp files
void ProcessDirectory(const char *directory, FILE *outFile) {
    char searchPath[MAX_PATH_LEN];
    // Build the search pattern (e.g., "C:\MyFolder\*")
    snprintf(searchPath, sizeof(searchPath), "%s\\*", directory);

    WIN32_FIND_DATA findData;
    HANDLE hFind = FindFirstFile(searchPath, &findData);
    if (hFind == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "Error opening directory: %s\n", directory);
        return;
    }

    do {
        // Skip the special entries "." and ".."
        if (strcmp(findData.cFileName, ".") == 0 ||
            strcmp(findData.cFileName, "..") == 0) {
            continue;
        }

        char fullPath[MAX_PATH_LEN];
        snprintf(fullPath, sizeof(fullPath), "%s\\%s", directory, findData.cFileName);

        // Check if this is a directory
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // Recurse into the subdirectory
            ProcessDirectory(fullPath, outFile);
        } else {
            // Check for a .bsp extension (case-insensitive)
            int len = (int)strlen(findData.cFileName);
            if (len >= 4 && _stricmp(findData.cFileName + len - 4, ".bsp") == 0) {
                ProcessBSPFile(fullPath, outFile);
            }
        }
    } while (FindNextFile(hFind, &findData));

    FindClose(hFind);
}

// Processes an individual .bsp file: reads the 5th byte and writes info if invalid.
void ProcessBSPFile(const char *filePath, FILE *outFile) {
    FILE *f = fopen(filePath, "rb");
    if (!f) {
        fprintf(outFile, "%s - Error opening file.\n", filePath);
        return;
    }

    unsigned char buffer[5];
    size_t bytesRead = fread(buffer, 1, 5, f);
    fclose(f);

    if (bytesRead < 5) {
        fprintf(outFile, "%s - File too short.\n", filePath);
        return;
    }

    // If the 5th byte (index 4) is 0x26, the file is valid—do not list it.
    if (buffer[4] == 0x26) {
        return;
    }

    // Write the file path to the output
    fprintf(outFile, "%s", filePath);

    // Append annotation based on the 5th byte value
    if (buffer[4] == 0x2E) {
        fprintf(outFile, " (Quake3, STVEF, or NExuiz)");
    } else if (buffer[4] == 0x29) {
        fprintf(outFile, " (Daikatana)");
    } else if (buffer[4] == 0x2F) {
        fprintf(outFile, " (RTCW)");
    }
    fprintf(outFile, "\n");
}
