#include "infoScreen.h"
#include "game.h"

// Fuck this capitalist society. Long live Karl Marx!

const EntityUserInfo infoScreenEntityInfo[INFO_SCREEN_ENTITY_COUNT] = {
    (EntityUserInfo){
        .type = ENTITY_ANTIFA,
        .assetId = ANTIFA_SHIP_ASSET,
        .cameraDistance = 15.0,
        .msg = "The player ship. Its a anti fascist ship and is completely bad ass."
    },
    (EntityUserInfo){
        .type = ENTITY_SOLDATO,
        .assetId = SOLDATO_ASSET,
        .cameraDistance = 15.0,
        .msg = "A wippy little ship. It follows the other ships like ants."
    },
    (EntityUserInfo){
        .type = ENTITY_CAPORALE,
        .assetId = CAPORATE_ASSET,
        .cameraDistance = 15.0,
        .msg = "A pretty normal space ship. Often acts as a leader for the soldato."
    },
    (EntityUserInfo){
        .type = ENTITY_SERGENTE,
        .assetId = SERGENTE_ASSET,
        .cameraDistance = 15.0,
        .msg = "A funny little dude that packs a lot of power"
    },
    (EntityUserInfo){
        .type = ENTITY_MARESCIALLO,
        .assetId = MARESCIALLO_ASSET,
        .cameraDistance = 15.0,
        .msg = "A sneaky little ship based on a stealth jet."
    },
    (EntityUserInfo)
    {
        .type = ENTITY_GENERALE,
        .assetId = GENERALE_ASSET,
        .cameraDistance = 15.0,
        .msg = "A ufo that goes zig zag and shoots its epic deadly laser.",
    },
    (EntityUserInfo){
        .type = ENTITY_MUSSOLINI,
        .assetId = MUSSOLINI_ASSET,
        .cameraDistance = 150.0,
        .msg = "A deadly mother fucker named after the Italian fascist dictator"
    }
};

void initInfoScreen(Game * game) {
    InfoScreen * infoScreen = &game->infoScreen;

    // Buttons.
    infoScreen->goBackButton = (Rectangle){0.0, 25.0, 100.0, 50.0};
    infoScreen->backButton = (Rectangle){0.0, 85.0, 100.0, 50.0};
    infoScreen->nextButton = (Rectangle){100.0, 85.0, 100.0, 50.0};
    infoScreen->resetButton = (Rectangle){0.0, 145.0, 100.0, 50.0};

    // Shitty thingy.
    infoScreen->controlsPosition = (Vector2){
        10.0,
        infoScreen->resetButton.y + infoScreen->resetButton.height + 10
    };

    // Camera.
    infoScreen->camera = (Camera3D){
        .position = (Vector3){0.0, 0.0, infoScreenEntityInfo[0].cameraDistance},
        .target = Vector3Zero(),
        .up = (Vector3){0.0, 1.0, 0.0},
        .fovy = 90.0,
        .projection = CAMERA_PERSPECTIVE
    };

    infoScreen->currentEntity = 0;

    infoScreen->resetMouse = true;

    // Set distances and roations.
    for (int i = 0; i < ENTITY_USER_INFO_MSG_MAX; ++i) {
        infoScreen->distances[i] = infoScreenEntityInfo[i].cameraDistance;
        infoScreen->rotations[i] = QuaternionIdentity();
    }

    resizeInfoScreen(game, infoScreen);
}

void updateInfoScreenCameraControls(Game * game, InfoScreen * infoScreen) {
    double t = GetFrameTime();
    Camera3D * camera = &infoScreen->camera;
    int currentEntity = infoScreen->currentEntity;

    // Reset mouse.
    if (infoScreen->resetMouse) {
        infoScreen->resetMouse = false;
        SetMousePosition(0, 0);
        infoScreen->lastMouse = Vector2Zero();
    }

    // Get mouse.
    Vector2 mousePosition = GetMousePosition();
    Vector2 mouseSpeed = Vector2Subtract(mousePosition, infoScreen->lastMouse);
    mouseSpeed = Vector2Scale(mouseSpeed, 1.0 / t);
    mouseSpeed = Vector2Scale(mouseSpeed, game->settings.previewMouseSensitivity);
    infoScreen->lastMouse = mousePosition;

    // Get mouse axis angle.
    AxisAngle angle = AxisAngleIdentity();
    angle.axis = (Vector3){mouseSpeed.y, mouseSpeed.x, 0.0};
    angle.angle = Vector3Length(angle.axis);

    if (IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) {
        angle.axis.z = mouseSpeed.x;
        angle.axis.y = 0.0;
    }

    // Apply rotation.
    Quaternion rotationSpeed = QuaternionFromAxisAngle(angle.axis, angle.angle * t);
    infoScreen->rotations[currentEntity] = QuaternionMultiply(infoScreen->rotations[currentEntity], rotationSpeed);
    infoScreen->rotations[currentEntity] = QuaternionNormalize(infoScreen->rotations[currentEntity]);
}

void updateInfoScreenCamera(Game * game, InfoScreen * infoScreen) {
    Camera3D * camera = &infoScreen->camera;
    int currentEntity = infoScreen->currentEntity;

    camera->position = (Vector3){0.0, 0.0, infoScreen->distances[currentEntity]};
}

void infoScreenBack(InfoScreen * infoScreen) {
    --infoScreen->currentEntity;
    infoScreen->currentEntity = Clamp(infoScreen->currentEntity, 0, INFO_SCREEN_ENTITY_COUNT - 1);
}

void infoScreenNext(InfoScreen * infoScreen) {
    ++infoScreen->currentEntity;
    infoScreen->currentEntity = Clamp(infoScreen->currentEntity, 0, INFO_SCREEN_ENTITY_COUNT - 1);
}

void infoScreenResetEntity(InfoScreen * infoScreen) {
    int currentEntity = infoScreen->currentEntity;

    infoScreen->resetMouse = true;
    infoScreen->rotations[currentEntity] = QuaternionIdentity();
    infoScreen->distances[currentEntity] = infoScreenEntityInfo[currentEntity].cameraDistance;
}

void drawInfoScreenUI(Game * game, InfoScreen * infoScreen) {
    int currentEntity = infoScreen->currentEntity;

    // Back to main menu button.
    if (GuiButton(infoScreen->goBackButton, "Main Menu"))
        game->screenId = SCREEN_MAIN_MENU;

    // Back button.
    if (GuiButton(infoScreen->backButton, "Back"))
        infoScreenBack(infoScreen);

    // Next button.
    if (GuiButton(infoScreen->nextButton, "Next"))
        infoScreenNext(infoScreen);

    // Reset button.
    if (GuiButton(infoScreen->resetButton, "Reset"))
        infoScreenResetEntity(infoScreen);

    // I need to tell the stupid players how to use this fucker.
    const char * stupidFuck = "-Right click and mouse to change angle\n"
    "-Middle click with right click for a different type of rotation\n"
    "-scroll wheel to zoom in and out\n"
    "-r to reset\n"
    "-right and left arrows to go to next and previous entities";

    DrawText(stupidFuck, infoScreen->controlsPosition.x, infoScreen->controlsPosition.y,
             ENTITY_INFO_FONT_SIZE, GREEN);

    // Draw ship name.
    EntityType type = infoScreenEntityInfo[currentEntity].type;
    const char * name = entityTypeInfo[type].name;
    size_t nameSize = strnlen(name, ENTITY_TYPE_INFO_NAME_MAX);

    DrawText(
        name,
        GetScreenWidth() / 2.0 - ((nameSize + 1) * (ENTITY_INFO_NAME_FONT_SIZE / 2.0) / 2.0),
        10.0,
        ENTITY_INFO_NAME_FONT_SIZE,
        GREEN
    );

    // Draw entity info.
    const char * msg = infoScreenEntityInfo[currentEntity].msg;
    size_t msgSize = strnlen(msg, ENTITY_USER_INFO_MSG_MAX);

    DrawText(
        msg,
        GetScreenWidth() / 2.0 - ((msgSize + 1) * (ENTITY_INFO_FONT_SIZE / 2.0) / 2.0),
        ENTITY_INFO_NAME_FONT_SIZE + 10,
        ENTITY_INFO_FONT_SIZE,
        GREEN
    );
}

void updateInfoScreen(Game * game) {
    InfoScreen * infoScreen = &game->infoScreen;
    int currentEntity = infoScreen->currentEntity;
    ClearBackground(BLACK);

    // Reset.
    if (IsKeyPressed(KEY_R))
       infoScreenResetEntity(infoScreen);

    // Change distance.
    infoScreen->distances[currentEntity] += -GetMouseWheelMove() * game->settings.previewZoomSpeed;

    // Handling hidding cursor and shit.
    if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
        DisableCursor();
    } else if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON)) {
        infoScreen->resetMouse = true;
        EnableCursor();
    }

    // Switching modes.
    if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) {
        updateInfoScreenCameraControls(game, infoScreen);
    } else {
        drawInfoScreenUI(game, infoScreen);
    }

    // Arrows.
    if (IsKeyPressed(KEY_LEFT))
        infoScreenBack(infoScreen);
    else if (IsKeyPressed(KEY_RIGHT))
        infoScreenNext(infoScreen);

    EntityUserInfo info = infoScreenEntityInfo[currentEntity];

    // Update camera.
    updateInfoScreenCamera(game, infoScreen);

    // Draw shit.
    BeginMode3D(infoScreen->camera);

    game->assets.models[info.assetId].transform = QuaternionToMatrix(infoScreen->rotations[currentEntity]);
    DrawModelWires(game->assets.models[info.assetId], Vector3Zero(), 1.0, GREEN);

    EndMode3D();
}

void resizeInfoScreen(Game * game, InfoScreen * infoScreen) {
}