#include "client/Game.h"
#include "common/network/Packets.h"
#include "utils/Utils.h"

Game::Game(TextInput*& textInput, const Controller& controller,
           const Clock& fps, const Clock& tps, RenderSettings& settings,
           const Size& size, Client& client)
    : controller(controller), fps(fps), tps(tps), renderSettings(settings),
      size(size), client(client), state(State::START),
      baseGUI(size, textInput, controller), startGUI(baseGUI),
      world(blockRegistry), worldRenderer(world), connected(false) {
    pos = Vector3(16.0f, 30.0f, -10.0f);
    rotation = Quaternion(Vector3(1.0f, 0.0f, 0.0f), 30) * rotation;
    rotation = Quaternion(Vector3(0.0f, 1.0f, 0.0f), 30) * rotation;
}

void Game::tick() {
    switch(state) {
        case State::START: startGUI.tick(); break;
    }
    /*if(!connected && controller.down.wasReleased()) {
        if(client.connect("127.0.0.1", 11196, 3000)) {
            std::cout << client.getError() << '\n';
        } else {
            std::cout << "connected\n";
        }
    } else {
        client.consumeEvents(*this);
    }*/

    lastRotation = rotation;
    lastPos = pos;

    Vector3 right = rotation * Vector3(1.0f, 0.0f, 0.0f);
    Vector3 up = rotation * Vector3(0.0f, 1.0f, 0.0f);
    Vector3 back = rotation * Vector3(0.0f, 0.0f, -1.0f);

    const float speed = 2.0f;
    if(controller.down.isDown()) {
        pos += back * speed;
    }
    if(controller.up.isDown()) {
        pos -= back * speed;
    }
    if(controller.left.isDown()) {
        pos -= right * speed;
    }
    if(controller.right.isDown()) {
        pos += right * speed;
    }
    if(controller.jump.isDown()) {
        pos += up * speed;
    }
    if(controller.sneak.isDown()) {
        pos -= up * speed;
    }

    const float rotationSpeed = 5.0f;
    if(controller.camLeft.isDown()) {
        rotation = Quaternion(up, -rotationSpeed) * rotation;
    }
    if(controller.camRight.isDown()) {
        rotation = Quaternion(up, rotationSpeed) * rotation;
    }
    if(controller.camUp.isDown()) {
        rotation = Quaternion(right, -rotationSpeed) * rotation;
    }
    if(controller.camDown.isDown()) {
        rotation = Quaternion(right, rotationSpeed) * rotation;
    }
}

void Game::renderWorld(float lag, ShaderMatrix& sm) {
    sm.update(Utils::interpolate(lastPos, pos, lag),
              lastRotation.lerp(lag, rotation));
    worldRenderer.render(lag, sm);
}

void Game::renderOverlay(float lag, ShaderMatrix& sm, Renderer& r) {
    switch(state) {
        case State::START: startGUI.render(lag, sm, r); break;
    }
    (void)lag;
    sm.identity().scale(2.0f).update();
    StringBuffer<100> s;
    s.append("FPS: &074")
        .append(fps.getUpdatesPerSecond())
        .append(" &999TPS: &722")
        .append(tps.getUpdatesPerSecond());
    r.drawString(Vector2(10.0f, 10.0f), s);
}

bool Game::isRunning() const {
    return true;
}

void Game::onConnect() {
}

void Game::onDisconnect() {
}

void Game::onPacket(InPacket& in) {
    uint16 id;
    if(in.readU16(id)) {
        return;
    }
    switch(id) {
        case ServerPacket::CHAT:
            StringBuffer<256> s;
            in.readString(s);
            std::cout << s << '\n';
            break;
    }
}