#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "raylib.h"
#include "search.h"

char color_to_facelet(char color) {
    switch (toupper(color)) {
        case 'W':
            return 'U';
        case 'Y':
            return 'D';
        case 'R':
            return 'R';
        case 'O':
            return 'L';
        case 'G':
            return 'F';
        case 'B':
            return 'B';
        default:
            return '?';
    }
}

int build_kociemba_string(const char* face_U, const char* face_R,
                          const char* face_F, const char* face_D,
                          const char* face_L, const char* face_B,
                          char* output_54) {

    const char* faces[6] = { face_U, face_R, face_F, face_D, face_L, face_B };
    int pos = 0;

    for (int i = 0; i < 6; i++) {
        if (strlen(faces[i]) != 9) return 0;

        for (int j = 0; j < 9; j++) {
            char c = color_to_facelet(faces[i][j]);
            if (c == '?') return 0;

            output_54[pos++] = c;
        }
    }
    output_54[54] = '\0';

    return 1;
}

int main(void) {
    InitWindow(1000, 900, "Rubik's Cube Solver");
    SetTargetFPS(67);

    Color cube_colors[6][9] = { 0 };
    Color palette[6] = { WHITE, YELLOW, RED, ORANGE, GREEN, BLUE };
    char palette_chars[6] = { 'W', 'Y', 'R', 'O', 'G', 'B' };

    const char* face_names[6] = { "Left", "Up", "Right",
                                  "Back", "Front", "Down" };

    int face_start_x[6] = { 200, 400, 600, 200, 400, 600 };
    int face_start_y[6] = { 100, 100, 100, 300, 300, 300 };

    int selected_color = 0;
    char solution_text[512] = "";
    int color_count[6] = {0};

    while (!WindowShouldClose()) {
        Vector2 mouse = GetMousePosition();

        BeginDrawing();
        ClearBackground(DARKGRAY);

        DrawText("Palette:", 50, GetScreenHeight() - 150, 20, WHITE);
        for (int i = 0; i < 6; i++) {
            int px = 50 + i * 60;
            int py = GetScreenHeight() - 120;

            DrawRectangle(px, py, 50, 50, palette[i]);
            if (i == selected_color) DrawRectangleLines(px, py, 50, 50, BLACK);

            DrawText(TextFormat("%c", palette_chars[i]), px + 15, GetScreenHeight() - 50, 20, WHITE);

            // maximum 9 of each color
            DrawText(TextFormat("%d", color_count[i]), px + 17, py + 15, 20, color_count[i] <= 9 ? BLACK : PINK);

            if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
                if (CheckCollisionPointRec(mouse, (Rectangle) {px, py, 50, 50} )) selected_color = i;
        }

        for (int f = 0; f < 6; f++) {
            int fx = face_start_x[f];
            int fy = face_start_y[f];
            DrawText(face_names[f], fx, fy - 30, 20, WHITE);

            for (int i = 0; i < 9; i++) {
                int x = fx + (i % 3) * 50;
                int y = fy + (i / 3) * 50;

                DrawRectangle(x, y, 48, 48, cube_colors[f][i]);
                DrawRectangleLines(x, y, 48, 48, BLACK);

                // maximum 9 of each color
                if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) /*&& color_count[selected_color] < 9*/) {
                    if (CheckCollisionPointRec(mouse, (Rectangle) { x, y, 48, 48 })) {
                        for (int p = 0; p < 6; p++) {
                            if (cube_colors[f][i].r == palette[p].r &&
                                cube_colors[f][i].g == palette[p].g &&
                                cube_colors[f][i].b == palette[p].b) {

                                color_count[p]--;
                                break;

                            }
                        }

                        cube_colors[f][i] = palette[selected_color];
                        color_count[selected_color]++;
                    }
                }
            }
        }

        Rectangle solve_btn = {100, 500, 150, 50};
        DrawRectangleRec(solve_btn, LIGHTGRAY);
        DrawRectangleLinesEx(solve_btn, 2, BLACK);

        DrawText("Solve Cube", 118, 515, 20, BLACK);
        DrawText("Solution:", 120, 570, 20, WHITE);
        DrawText(solution_text, 120, 590, 20, GREEN);
        EndDrawing();

        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) &&
            CheckCollisionPointRec(mouse, solve_btn)) {
            char faces[6][10] = {0};

            for (int f = 0; f < 6; f++)
                for (int i = 0; i < 9; i++)
                    for (int p = 0; p < 6; p++)
                        if (cube_colors[f][i].r == palette[p].r &&
                            cube_colors[f][i].g == palette[p].g &&
                            cube_colors[f][i].b == palette[p].b) {
                            faces[f][i] = palette_chars[p];

                            break;
                        }

            char kociemba[55];
            if (!build_kociemba_string(faces[1], faces[2], faces[4],
                                       faces[5], faces[0], faces[3], kociemba)) {
                strcpy(solution_text, "Invalid cube!");

                continue;
            }

            char* sol = solution(kociemba, 6767, 6767, 6767, "cache");
            if (!sol) {

                strcpy(solution_text, "No solution!");

            } else if (strncmp(sol, "ERROR", 5) == 0) {

                strncpy(solution_text, sol, sizeof(solution_text) - 1);
                solution_text[sizeof(solution_text) - 1] = '\0';

            } else {

                strncpy(solution_text, sol, sizeof(solution_text) - 1);
                solution_text[sizeof(solution_text) - 1] = '\0';

            }

            free(sol);
        }
    }
    CloseWindow();

    return 0;
}
