#include <game/agame/player.hpp>
#include <window/window.hpp>
#include <cmath>
#include <game/input.hpp>
#include <game/gamemanager.hpp>
#include <utils.hpp>

namespace Game::AGame {
    void Player::setShipTexture(std::shared_ptr<Game::Renderer::Texture> tex) {
        mShipTex = std::move(tex);
        if (mIsShipMode && mShipTex) {
            setTexture(mShipTex);
        }
    }

    void Player::setGroundTexture(std::shared_ptr<Game::Renderer::Texture> tex) {
        mGroundTex = std::move(tex);
        if (!mIsShipMode && mGroundTex) {
            setTexture(mGroundTex);
        }
    }

    void Player::respawnRandomSea(float landBoundaryX) {
        auto spawnTex = mShipTex ? mShipTex : mTex;
        if (!spawnTex) {
            return;
        }

        int w = 0;
        int h = 0;
        SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &w, &h);

        const float halfWidth = spawnTex->getWidth() * mTransform.adjustedScaleX() / 2.f;
        const float halfHeight = spawnTex->getHeight() * mTransform.adjustedScaleY() / 2.f;

        const float minCenterX = landBoundaryX + mShoreMargin + halfWidth;
        const float maxCenterX = w / 2.f - halfWidth - 10.f;
        const float minCenterY = -h / 2.f + halfHeight;
        const float maxCenterY = h / 2.f - halfHeight;

        float centerX = minCenterX;
        if (maxCenterX > minCenterX) {
            centerX = static_cast<float>(Utils::getUtils().rirng32(static_cast<int>(minCenterX), static_cast<int>(maxCenterX)));
        }

        float centerY = 0.f;
        if (maxCenterY > minCenterY) {
            centerY = static_cast<float>(Utils::getUtils().rirng32(static_cast<int>(minCenterY), static_cast<int>(maxCenterY)));
        }

        mTransform.x = centerX - halfWidth;
        mTransform.y = centerY - halfHeight;

        mIsShipMode = true;
        if (mShipTex) {
            setTexture(mShipTex);
        }
    }

    void Player::start() {
        //mSound = Object::Sound("../resources/example.wav", Object::Format::WAV);
        //mSound.play();
        mZIndex = 100;
        Game::GameManager::setSharedData("gameStage", 1);
        Game::GameManager::setSharedData("gameScore", 0);

        mTransform.scaleX = 8.f;
        mTransform.scaleY = 8.f;

        if (!mShipTex) {
            mShipTex = mTex;
        }
        if (!mGroundTex) {
            mGroundTex = mTex;
        }

        int w = 0;
        int h = 0;
        SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &w, &h);

        const float halfWidth = mTex->getWidth() * mTransform.adjustedScaleX() / 2.f;
        const float halfHeight = mTex->getHeight() * mTransform.adjustedScaleY() / 2.f;
        const float minX = -w / 2.f + halfWidth;
        const float maxX = w / 2.f - halfWidth;
        const float minY = -h / 2.f + halfHeight;
        const float maxY = h / 2.f - halfHeight;

        const float landBoundaryX = Game::GameManager::getSharedData<float>("terrainLandBoundaryX");
        mTransform.x = static_cast<float>(Utils::getUtils().rirng32(static_cast<int>(minX), static_cast<int>(maxX)));
        mTransform.y = static_cast<float>(Utils::getUtils().rirng32(static_cast<int>(minY), static_cast<int>(maxY)));
        mIsShipMode = (mTransform.x + halfWidth) >= landBoundaryX;

        mTransform.x -= mTex->getWidth() * mTransform.adjustedScaleX() / 2.f;
        mTransform.y -= mTex->getHeight() * mTransform.adjustedScaleY() / 2.f;

        if (mIsShipMode && mShipTex) {
            setTexture(mShipTex);
        } else if (!mIsShipMode && mGroundTex) {
            setTexture(mGroundTex);
        }

        LOG("Š: " << w << " V: " << h);
        //mSound.~Sound();
    }

    void Player::update(float deltaTime) {
        //mTransform.rotation += 1.f; // Rotate clockwise for testing
        //mTransform.scaleX = 1.f + 1.f * std::sin(RUNNING_TIME() / 0.5f); // Pulsate scale for testing
        //mTransform.scaleY = 1.f + 0.5f * std::cos(RUNNING_TIME() / 0.5f); // Pulsate scale for testing
        //Object::Camera::getInstance().move(1.f, 0.f);

        const float landBoundaryX = Game::GameManager::getSharedData<float>("terrainLandBoundaryX");
        const float halfWidth = mTex->getWidth() * mTransform.adjustedScaleX() / 2.f;

        if (Input::isKeyPressed(SDL_SCANCODE_E)) {
            const bool nearShore = std::abs((mTransform.x + halfWidth) - landBoundaryX) <= mShoreMargin;
            if (nearShore) {
                mIsShipMode = !mIsShipMode;
            }
        }

        // Simple movement
        if (Input::isKeyPressed(SDL_SCANCODE_W)) { mTransform.y -= mSpeed * deltaTime; }
        if (Input::isKeyPressed(SDL_SCANCODE_S)) { mTransform.y += mSpeed * deltaTime; }
        if (Input::isKeyPressed(SDL_SCANCODE_A)) { mTransform.x -= mSpeed * deltaTime; mIsFlipped = false; }
        if (Input::isKeyPressed(SDL_SCANCODE_D)) { mTransform.x += mSpeed * deltaTime; mIsFlipped = true; }
        mSpeed = Input::isKeyPressed(SDL_SCANCODE_LSHIFT) ? 400.f : 200.f;

        int w = 0;
        int h = 0;
        SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &w, &h);
        const float entityWidth = mTex ? mTex->getWidth() * mTransform.adjustedScaleX() : 0.f;
        const float entityHeight = mTex ? mTex->getHeight() * mTransform.adjustedScaleY() : 0.f;
        const float minX = -w / 2.f;
        const float maxX = w / 2.f - entityWidth;
        const float minY = -h / 2.f;
        const float maxY = h / 2.f - entityHeight;

        if (mTransform.x < minX) mTransform.x = minX;
        if (mTransform.x > maxX) mTransform.x = maxX;
        if (mTransform.y < minY) mTransform.y = minY;
        if (mTransform.y > maxY) mTransform.y = maxY;

        if (mIsShipMode && (mTransform.x + halfWidth) < landBoundaryX + mShoreMargin) {
            mTransform.x = landBoundaryX + mShoreMargin - halfWidth;
        }
        if (!mIsShipMode && (mTransform.x + halfWidth) > landBoundaryX - mShoreMargin) {
            mTransform.x = landBoundaryX - mShoreMargin - halfWidth;
        }

        if (mIsShipMode && mShipTex) {
            setTexture(mShipTex);
        } else if (!mIsShipMode && mGroundTex) {
            setTexture(mGroundTex);
        }
    }

    void Player::onCollisionEnter(Object::Entity* other) {
        (void)other;
        if (GameManager::getSharedData<bool>("gameLost")) {
            GameManager::destroyEntity(this);
        }
    }
}