#include <stdio.h>

#include "raylib.h"
#include "raymath.h"

#define ROPE_LEN 20
#define ROPE_WIDTH 10

#define NB_ROPE 50
Vector2 ropes[NB_ROPE];
Vector2 forces[NB_ROPE];

#define ENEMIE_WIDTH 25
#define NB_ENEMIE 10
Vector2 enemies[NB_ENEMIE];

int points = -NB_ENEMIE;

Vector2 window = {1920, 1080};

int main()
{
    SetRandomSeed(69);
    InitWindow(window.x, window.y, "speedrun");
    SetWindowState(FLAG_FULLSCREEN_MODE|FLAG_WINDOW_RESIZABLE);
    HideCursor();
    SetTargetFPS(60);

    for (int i = 0; i < NB_ROPE; i++) {
        ropes[i] = (Vector2) {window.x/2, window.y/2};
    }

    while (!WindowShouldClose()) {

        if (IsWindowResized()) {
            window.x = GetScreenWidth();
            window.y = GetScreenHeight();
        }

        static int is_space = 0;
        if (IsKeyPressed(KEY_SPACE)) {
            is_space = !is_space;
        }

        BeginDrawing();
        {
            ClearBackground(GRAY);

            if (GetTime() < 5) {
                int size = 75;
                const char* info = "Soak your spaghetti in Bolognese sauce !";
                DrawText(
                    info,
                    window.x / 2 - MeasureText(info, size) / 2,
                    window.y / 2 - size,
                    size, GOLD
                );
                const char* mode = "Press space to change mode";
                DrawText(
                    mode,
                    window.x / 2 - MeasureText(mode, size) / 2,
                    window.y / 2,
                    size, SKYBLUE
                );
            }

            if (points > (NB_ROPE-1)*10) {
                ShowCursor();

                static int off = 0;
                off++;

                DrawCircleV(ropes[0], ROPE_WIDTH/2, ColorFromHSV(off%360, 1, 1));

                for (int i = 1; i < NB_ROPE; i++) {
                    Color c = ColorFromHSV((off+i*3)%360, 1, 1);

                    DrawCircleV(ropes[i], ROPE_WIDTH/2, c);
                    DrawLineEx(ropes[i-1], ropes[i], ROPE_WIDTH, c);
                }

                int size = 75;
                DrawText("YOU WON!", window.x/2-MeasureText("YOU WON!", size)/2, window.y/2-size/2, size, GOLD);

                EndDrawing();
                continue;
            }

            ropes[0] = GetMousePosition();
            DrawCircleV(ropes[0], ROPE_WIDTH/2, points > 0 ? RED : YELLOW);

            for (int i = 1; i < NB_ROPE; i++) {
                Vector2 old = ropes[i];

                if (!is_space)
                    forces[i].y += 9.8*69*GetFrameTime();

                ropes[i] = Vector2Add(ropes[i], forces[i]);

                float dist = Vector2Distance(ropes[i-1], ropes[i]);
                if (!dist) dist = ROPE_LEN;
                ropes[i] = Vector2Lerp(ropes[i-1], ropes[i], ROPE_LEN/dist);

                Vector2 snap = Vector2Subtract(old, ropes[i]);
                snap = Vector2Negate(snap);
                snap = Vector2Scale(snap, GetFrameTime()*37);

                forces[i] = snap;

                Color color = YELLOW;
                if (i*10 < points) color = RED;

                DrawCircleV(ropes[i], ROPE_WIDTH/2, color);
                DrawLineEx(ropes[i-1], ropes[i], ROPE_WIDTH, color);

                for (int y = 0; y < NB_ENEMIE; y++) {
                    if (CheckCollisionCircles(enemies[y], ENEMIE_WIDTH, ropes[i], ROPE_WIDTH/2)) {
                        points++;
                        enemies[y].x = -500;
                        enemies[y].y = -500;
                    }
                }
            }

            for (int i = 0; i < NB_ENEMIE; i++) {
                if (!CheckCollisionCircleRec(enemies[i], 50, (Rectangle){0,0,window.x,window.y})) {
                    int side = GetRandomValue(0, 3);
                    float pour = (float)GetRandomValue(0, 100)/100;
                    switch (side) {
                    case 0: // left
                        enemies[i].x = -ENEMIE_WIDTH;
                        enemies[i].y = pour*window.y;
                        break;
                    case 1: // top
                        enemies[i].x = pour*window.x;
                        enemies[i].y = -ENEMIE_WIDTH;
                        break;
                    case 2: // right
                        enemies[i].x = window.x+ENEMIE_WIDTH;
                        enemies[i].y = pour*window.y;
                        break;
                    case 3: // bottom
                        enemies[i].x = pour*window.x;
                        enemies[i].y = window.y+ENEMIE_WIDTH;
                        break;
                    }
                    continue;
                }
                enemies[i].x += (i+50)*GetFrameTime() * (i%2 ? -i/5-1 :  i/3+1);
                enemies[i].y += (i+50)*GetFrameTime() * (i%3 ?  i/2+1 : -i/2-1);
                DrawCircleV(enemies[i], ENEMIE_WIDTH, RED);
            }

            int size = 30;
            int marg = 5;
            DrawText(" Mode: ", 0, marg, size, ORANGE);
            if (is_space) {
                DrawText("SPACE", MeasureText(" Mode: ", size), marg, size, DARKBLUE);
            } else {
                DrawText("GRAVITY", MeasureText(" Mode: ", size), marg, size, BROWN);
            }
            DrawText(" Points: ", 0, size+marg, size, ORANGE);
            DrawText(TextFormat("%d / %d", points, 10*NB_ROPE), MeasureText(" Points: ", size), size+marg, size, GOLD);
        }
        EndDrawing();
    }
}