#include "game.h"      // Enthält Definitionen wie MAX_SEARCH_FIELD_LEN und MAX_WORD_LEN
#include <time.h>      // Für Zeitfunktionen, z. B. zur Initialisierung von Zufallszahlen
#include <stdlib.h>    // Für rand(), malloc(), etc.
#include <string.h>    // Für Stringfunktionen wie strnlen()
#include <ctype.h>     // Für toupper(), um Buchstaben in Großbuchstaben umzuwandeln
#include <stdio.h>     // Für printf(), um das Spielfeld auszugeben

#define MAX_RAND_TRIES_PER_WORD 10  // Maximale Anzahl zufälliger Platzierungsversuche pro Wort
#define EMPTY_CHAR 0                // Kennzeichnung für ein leeres Feld im Spielfeld

// Prüft, ob ein Wort an Position (x,y) in gegebener Richtung ins Spielfeld passt
// dir = 0 → horizontal; dir = 1 → vertikal
static int canPlaceAt(const char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN],
                      unsigned int searchFieldLen,
                      unsigned int x, unsigned int y,
                      const char *word, unsigned int wordLen,
                      int dir)
{
    if (dir == 0) { // horizontal
        // Prüfen, ob das Wort über den rechten Rand hinausgeht
        if (x + wordLen > searchFieldLen) return 0;

        // Prüfen, ob jedes Zeichen entweder leer ist oder bereits passt
        for (unsigned int k = 0; k < wordLen; ++k) {
            char c = (char)toupper((unsigned char)word[k]); // Zeichen in Großbuchstaben
            char cell = salad[y][x + k]; // Aktuelles Feld
            if (cell != EMPTY_CHAR && cell != c) return 0; // Konflikt → nicht platzierbar
        }
    } else { // vertikal
        // Prüfen, ob das Wort über den unteren Rand hinausgeht
        if (y + wordLen > searchFieldLen) return 0;

        for (unsigned int k = 0; k < wordLen; ++k) {
            char c = (char)toupper((unsigned char)word[k]);
            char cell = salad[y + k][x];
            if (cell != EMPTY_CHAR && cell != c) return 0;
        }
    }
    return 1; // Wort kann platziert werden
}

// Trägt ein Wort an Position (x,y) in gegebener Richtung ins Spielfeld ein
static void placeAt(char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN],
                    unsigned int x, unsigned int y,
                    const char *word, unsigned int wordLen,
                    int dir)
{
    if (dir == 0) { // horizontal
        for (unsigned int k = 0; k < wordLen; ++k) {
            salad[y][x + k] = (char)toupper((unsigned char)word[k]);
        }
    } else { // vertikal
        for (unsigned int k = 0; k < wordLen; ++k) {
            salad[y + k][x] = (char)toupper((unsigned char)word[k]);
        }
    }
}

// Erstellt das Wortsuchfeld, platziert Wörter und füllt leere Felder mit Zufallsbuchstaben
// Rückgabewert: Anzahl der erfolgreich platzierten Wörter
int createWordSalad(char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN],
                    unsigned int searchFieldLen,
                    const char words[][MAX_WORD_LEN],
                    unsigned int wordCount)
{
    // Ungültige Feldgröße → nichts tun
    if (searchFieldLen == 0 || searchFieldLen > MAX_SEARCH_FIELD_LEN) {
        return 0;
    }

    // Initialisiere das Spielfeld mit EMPTY_CHAR
    for (unsigned int r = 0; r < searchFieldLen; ++r) {
        for (unsigned int c = 0; c < searchFieldLen; ++c) {
            salad[r][c] = EMPTY_CHAR;
        }
    }

    int placedCount = 0; // Zähler für erfolgreich platzierte Wörter

    // Versuche, jedes Wort zu platzieren
    for (unsigned int i = 0; i < wordCount; ++i) {
        const char *word = words[i];
        if (!word) continue;

        size_t rawLen = strnlen(word, MAX_WORD_LEN); // Wortlänge ermitteln
        if (rawLen == 0) continue;

        unsigned int wordLen = (unsigned int)rawLen;

        // Wenn das Wort zu lang ist, überspringen
        if (wordLen > searchFieldLen) {
            continue;
        }

        int placed = 0; // Flag, ob das Wort platziert wurde

        // Zufällige Platzierungsversuche
        for (int t = 0; t < MAX_RAND_TRIES_PER_WORD && !placed; ++t) {
            int dir = rand() % 2; // Richtung zufällig wählen: 0 = horizontal, 1 = vertikal

            // Berechnung der maximalen Startpositionen
            unsigned int maxX = (dir == 0) ? (searchFieldLen - wordLen) : (searchFieldLen - 1);
            unsigned int maxY = (dir == 1) ? (searchFieldLen - wordLen) : (searchFieldLen - 1);

            // Zufällige Startposition innerhalb der Grenzen
            unsigned int x = (maxX > 0) ? (unsigned int)(rand() % (maxX + 1)) : 0;
            unsigned int y = (maxY > 0) ? (unsigned int)(rand() % (maxY + 1)) : 0;

            // Prüfen und ggf. platzieren
            if (canPlaceAt(salad, searchFieldLen, x, y, word, wordLen, dir)) {
                placeAt(salad, x, y, word, wordLen, dir);
                placed = 1;
            }
        }

        // Fallback: systematische Suche, falls Zufall nicht funktioniert hat
        if (!placed) {
            for (int dir = 0; dir < 2 && !placed; ++dir) {
                unsigned int limitX = (dir == 0) ? (searchFieldLen - wordLen + 1) : searchFieldLen;
                unsigned int limitY = (dir == 1) ? (searchFieldLen - wordLen + 1) : searchFieldLen;

                for (unsigned int y = 0; y < limitY && !placed; ++y) {
                    for (unsigned int x = 0; x < limitX && !placed; ++x) {
                        if (canPlaceAt(salad, searchFieldLen, x, y, word, wordLen, dir)) {
                            placeAt(salad, x, y, word, wordLen, dir);
                            placed = 1;
                        }
                    }
                }
            }
        }

        if (placed) {
            placedCount++; // Erfolgreich platziertes Wort zählen
        }
        // Nicht platzierbare Wörter werden ignoriert
    }

    // Fülle alle verbleibenden Felder mit zufälligen Buchstaben
    for (unsigned int r = 0; r < searchFieldLen; ++r) {
        for (unsigned int c = 0; c < searchFieldLen; ++c) {
            if (salad[r][c] == EMPTY_CHAR) {
                salad[r][c] = (char)('A' + (rand() % 26)); // Zufallsbuchstabe A–Z
            }
        }
    }

    return placedCount; // Anzahl der platzierten Wörter zurückgeben
}

// Gibt das fertige Wortsuchfeld auf der Konsole aus
void showWordSalad(const char salad[MAX_SEARCH_FIELD_LEN][MAX_SEARCH_FIELD_LEN],
                   unsigned int searchFieldLen)
{
    for (unsigned int r = 0; r < searchFieldLen; ++r) {
        for (unsigned int c = 0; c < searchFieldLen; ++c) {
            char ch = salad[r][c]; // Zeichen aus dem Feld
            printf("%c ", ch);     // Ausgabe mit Leerzeichen
        }
        printf("\n"); // Zeilenumbruch nach jeder Reihe
    }
}