#include "gamecube.h"
#include <algorithm>
#include <ctime>
#include <vector>
#include "raylib.h" // Stellen Sie sicher, dass raylib.h hier oder in gamecube.h inkludiert ist


// -----------------------------------------------------------
// 3D Memory Game – Hauptprogramm
// -----------------------------------------------------------

enum GameScreen {MENU = 0, GAMEPLAY};


void SetupGame(std::vector<gamecube>& cubes, int pairs)
{
    cubes.clear();
    Color colors[] = {RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, WHITE, SKYBLUE};
    std::vector<Vec3> positions;

    int count = pairs * 2;
    int cols = 3;
    int rows = 2;
    if (count > 6) {
        cols = 4;
        rows = 3;
    }
    int index = 0;
    // Generiert Positionen basierend auf der Größe
    for (int r = 0; r < rows && index < count; ++r) {
        for (int c = 0; c < cols && index < count; ++c) {
            // Zentriert die Würfel um (0,0,0)
            positions.push_back({(float)c * 2.0f - (cols -1 ), 0.0f, (float)r * 2.0f - (rows -1)});
            index++;
        }
    }

    std::vector<Color> colorPool;
    for (int i = 0; i < pairs; i++) {
        colorPool.push_back(colors[i]);
        colorPool.push_back(colors[i]);
    }

    // Fisher-Yates Shuffle
    for (int i= colorPool.size() -1; i > 0; --i) {
        int j = rand() % (i + 1);
        std::swap(colorPool[i], colorPool[j]);
    }

    // Würfel erstellen
    for (int i = 0; i < count; i++)
        cubes.emplace_back(positions[i], colorPool[i]);

}

int main()
{
    // Zufall initialisieren#include "gamecube.h"
    //#include <algorithm>
    //#include <ctime>
    //
    //// -----------------------------------------------------------
    //// 3D Memory Game – Hauptprogramm
    //// -----------------------------------------------------------
    //int main()
    //{
    //    // Zufall initialisieren
    //    srand(time(NULL));
    //
    //    // Fenster und Kamera
    //    InitWindow(800, 600, "3D Memory Game with Matrix3D Library");
    //    SetTargetFPS(60);
    //
    //    Camera3D camera{};
    //    camera.position = {6.0f, 6.0f, 6.0f};
    //    camera.target   = {0.0f, 0.0f, 0.0f};
    //    camera.up       = {0.0f, 1.0f, 0.0f};
    //    camera.fovy     = 45.0f;
    //    camera.projection = CAMERA_PERSPECTIVE;
    //
    //    // Nur 3 Farben für 3 Paare
    //    Color colors[] = { RED, GREEN, BLUE };
    //
    //    // 6 Karten-Positionen im 3x2 Raster
    //    std::vector<Vec3> positions = {{-2, 0, -2}, {0, 0, -2}, {2, 0, -2},{-2, 0,  0}, {0, 0,  0}, {2, 0,  0}};
    //
    //    // Farben doppelt in einen Pool legen und mischen
    //    std::vector<Color> colorPool;
    //    for (int i = 0; i < 3; i++)
    //    {
    //        colorPool.push_back(colors[i]);
    //        colorPool.push_back(colors[i]);
    //    }
    //
    //    // Fisher-Yates Shuffle mit rand()
    //    for (int i = colorPool.size() - 1; i > 0; --i)
    //    {
    //        int j = rand() % (i + 1);   // Zufallsindex von 0 bis i
    //        std::swap(colorPool[i], colorPool[j]);
    //    }
    //
    //    // Karten/Würfel erstellen
    //    std::vector<gamecube> cubes;
    //    for (int i = 0; i < 6; i++)
    //        cubes.emplace_back(positions[i], colorPool[i]);
    //
    //    gamecube* first  = nullptr;
    //    gamecube* second = nullptr;
    //    float flipSpeed = 5.0f;  // Drehgeschwindigkeit
    //    bool gameWon = false;
    //
    //    // -----------------------------------------------------------
    //    // Hauptspielschleife
    //    // -----------------------------------------------------------
    //    while (!WindowShouldClose())
    //    {
    //        // Klick-Erkennung
    //        if (!gameWon && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
    //        {
    //            Vector2 mouse = GetMousePosition();
    //
    //            for (auto &c : cubes)
    //            {
    //                if (!c.IsFlipped() && !c.IsMatched())
    //                {
    //                    Vector2 screenPos = GetWorldToScreen({c.GetPosition().x, c.GetPosition().y, c.GetPosition().z}, camera);
    //
    //                    if (fabs(mouse.x - screenPos.x) < 40 && fabs(mouse.y - screenPos.y) < 40)
    //                        c.FlipForward();
    //                }
    //            }
    //        }
    //
    //        // Animation aller Würfel
    //        for (auto &c : cubes)
    //        {
    //            c.Update(flipSpeed);
    //
    //            // Sobald ein Würfel vollständig umgedreht ist → merken
    //            if (c.IsFlipped() && !c.IsMatched())
    //            {
    //                if (!first) first = &c;
    //                else if (!second && &c != first) second = &c;
    //            }
    //        }
    //
    //        // Matching-Logik
    //        if (first && second)
    //        {
    //            Color col1 = first->GetColor();
    //            Color col2 = second->GetColor();
    //
    //            if (col1.r == col2.r && col1.g == col2.g && col1.b == col2.b)
    //            {
    //                first->SetMatched(true);
    //                second->SetMatched(true);
    //            }
    //            else
    //            {
    //                first->FlipBackward();
    //                second->FlipBackward();
    //            }
    //
    //            first = second = nullptr;
    //        }
    //
    //        // Gewinnprüfung
    //        if (!gameWon)
    //            gameWon = std::all_of(cubes.begin(), cubes.end(), [](const gamecube &c){ return c.IsMatched(); });
    //
    //        // -----------------------------------------------------------
    //        // Zeichnen
    //        // -----------------------------------------------------------
    //        BeginDrawing();
    //        ClearBackground(RAYWHITE);
    //        BeginMode3D(camera);
    //
    //        for (auto &c : cubes)
    //            c.Draw();
    //
    //        EndMode3D();
    //
    //        if (gameWon)
    //            DrawText("Congrats! You found all pairs!", 150, 260, 30, DARKBLUE);
    //        else
    //            DrawText("Flip 2 cubes - find matching pairs!", 10, 10, 20, DARKGRAY);
    //
    //        EndDrawing();
    //    }
    //
    //    CloseWindow();
    //    return 0;
    //}
    srand(time(NULL));
    double startTime = 0.0;
    double endTime = 0.0;
    bool timerStarted = false;

    GameScreen currentScreen = MENU;
    int selectedPairs = 3;

    // 1. SPIELSPEZIFISCHE VARIABLEN HIER DEKLARIEREN (ohne Initialisierung)
    std::vector<gamecube> cubes;
    gamecube* first  = nullptr;
    gamecube* second = nullptr;
    float flipSpeed = 5.0f;  // Drehgeschwindigkeit
    bool gameWon = false;
    int moves = 0;


    // Fenster und Kamera
    InitWindow(800, 600, "3D Memory Game with Matrix3D Library");
    SetTargetFPS(60);

    Camera3D camera{};
    camera.position = {6.0f, 6.0f, 6.0f};
    camera.target   = {0.0f, 0.0f, 0.0f};
    camera.up       = {0.0f, 1.0f, 0.0f};
    camera.fovy     = 45.0f;
    camera.projection = CAMERA_PERSPECTIVE;

    // -----------------------------------------------------------
    // Hauptspielschleife
    // -----------------------------------------------------------
    while (!WindowShouldClose())
    {
        // -------------------------------------------------------
        // UPDATE-LOGIK NACH ZUSTAND
        // -------------------------------------------------------
        switch (currentScreen)
        {
            case MENU:
            {
                // Menü-Abfrage: Auf Tastendruck warten
                if (IsKeyPressed(KEY_THREE)) {
                    selectedPairs = 3; // 6 Würfel
                    SetupGame(cubes, selectedPairs);
                    gameWon = false;
                    first = second = nullptr;
                    currentScreen = GAMEPLAY;
                    timerStarted = false; // Timer-Reset
                    moves = 0;

                } else if (IsKeyPressed(KEY_SIX)) {
                    selectedPairs = 6; // 12 Würfel
                    SetupGame(cubes, selectedPairs);
                    gameWon = false;
                    first = second = nullptr;
                    currentScreen = GAMEPLAY;
                    timerStarted = false; // Timer-Reset
                    moves = 0;

                }
                break;
            }

            case GAMEPLAY:
            {
                // Timer starten
                if (!timerStarted)
                {
                    startTime = GetTime();
                    timerStarted = true;
                }
                // Klick-Erkennung (Ray Picking) – nur wenn noch nicht 2 ausgewählt sind
                if (!gameWon && IsMouseButtonPressed(MOUSE_LEFT_BUTTON) && (second == nullptr))
                {
                    Vector2 mouse = GetMousePosition();
                    Ray ray = GetMouseRay(mouse, camera);

                    gamecube* hitCube = nullptr;
                    float bestDist = 1e9f;

                    for (auto &c : cubes)
                    {
                        if (c.IsMatched() || c.IsFlipped()) continue;

                        Vec3 p = c.GetPosition();

                        BoundingBox box;
                        box.min = { p.x - 0.75f, p.y - 0.75f, p.z - 0.75f };
                        box.max = { p.x + 0.75f, p.y + 0.75f, p.z + 0.75f };

                        RayCollision col = GetRayCollisionBox(ray, box);
                        if (col.hit && col.distance < bestDist)
                        {
                            bestDist = col.distance;
                            hitCube = &c;
                        }
                    }

                    if (hitCube)
                    {
                        if (!first)
                        {
                            first = hitCube;
                            first->FlipForward();
                        }
                        else if (hitCube != first)
                        {
                            second = hitCube;
                            second->FlipForward();
                        }
                    }
                }

                // Animation aller Würfel (KEINE first/second Auto-Zuweisung hier!)
                for (auto &c : cubes)
                {
                    c.Update(flipSpeed);
                }

                // Matching-Logik: erst wenn beide vollständig umgedreht sind
                if (first && second && first->IsFlipped() && second->IsFlipped())
                {
                    moves++;

                    Color col1 = first->GetColor();
                    Color col2 = second->GetColor();

                    if (col1.r == col2.r && col1.g == col2.g && col1.b == col2.b)
                    {
                        first->SetMatched(true);
                        second->SetMatched(true);
                    }
                    else
                    {
                        first->FlipBackward();
                        second->FlipBackward();
                    }

                    first = nullptr;
                    second = nullptr;
                }

                // Gewinnprüfung
                if (!gameWon)
                {
                    // Prüft, ob ALLE Würfel gematcht sind
                    gameWon = std::all_of(cubes.begin(), cubes.end(), [](const gamecube &c){ return c.IsMatched(); });
                    if (gameWon)
                    {
                        endTime = GetTime() - startTime;
                    }
                }
                break;
            } // ENDE GAMEPLAY UPDATE
        }

        // -----------------------------------------------------------
        // ZEICHNEN NACH ZUSTAND
        // -----------------------------------------------------------
        BeginDrawing();
        ClearBackground(RAYWHITE);

        switch (currentScreen)
        {
            case MENU:
            {
                // Menü-Darstellung
                DrawText("3D MEMORY SPIEL", GetScreenWidth() / 2 - MeasureText("3D MEMORY SPIEL", 50) / 2, 80, 50, DARKGRAY);
                DrawText("Waehlen Sie die Spielgroesse:", 50, 200, 25, BLACK);
                DrawText("Druecken Sie [3] fuer 3 Paare (6 Wuerfel)", 50, 240, 20, BLUE);
                DrawText("Druecken Sie [6] fuer 6 Paare (12 Wuerfel)", 50, 280, 20, BLUE);
                break;
            }

            case GAMEPLAY:
            {
                // Spiel-Darstellung
                BeginMode3D(camera);

                for (auto &c : cubes)
                    c.Draw();

                EndMode3D();

                if (gameWon)
                {
                    DrawText("Congrats! You found all pairs!", 150, 260, 30, DARKBLUE);
                    char buffer[64];
                    sprintf(buffer, "Cleared in %.2f seconds", endTime);
                    DrawText(buffer, 150, 300, 28, DARKGREEN);
                }
                else
                {
                    DrawText("Flip 2 cubes - find matching pairs!", 10, 10, 20, DARKGRAY);
                    char liveBuf[64];
                    sprintf(liveBuf, "Time: %.2f", GetTime() - startTime);
                    DrawText(liveBuf, 10, 40, 20, DARKGRAY);

                    char moveBuf[64];
                    snprintf(moveBuf, sizeof(moveBuf), "Moves: %d", moves);
                    DrawText(moveBuf, 10, 70, 20, DARKGRAY);

                }
                break;
            } // ENDE GAMEPLAY DRAW
        }

        EndDrawing();
    }

    CloseWindow();
    return 0;
}