#include <game/agame/enemy.hpp>
#include <game/agame/background.hpp>
#include <object/components/boxcollider.hpp>
#include <game/agame/player.hpp>
#include <state/gamestate.hpp>
#include <algorithm>
#include <cmath>
#include <utils.hpp>
#include <game/gamemanager.hpp>
#include <window/window.hpp>

namespace Game::AGame {
    void Enemy::start() {
        mZIndex = 20;
        addComponent<Object::Components::BoxCollider>();
        LOG("Sovražnik zagnan: " << getName());
        
        // Initialize random movement
        const float angle = static_cast<float>(Utils::getUtils().rirng32(0, 360)) * 3.14159f / 180.f;
        const float speed = 20.f + static_cast<float>(Utils::getUtils().rirng32(0, 30));
        mMoveSpeedX = std::cos(angle) * speed;
        mMoveSpeedY = std::sin(angle) * speed;
        mDirectionChangeTimer = 0.f;
    }

    void Enemy::update(float deltaTime) {
        (void)deltaTime;

        auto* player = GameManager::getEntityByName<Player>("Player");
        if (!player) {
            mIsVisible = false;
            return;
        }

        // Enemies are visible only within a reveal radius around the player
        const float revealRadius = GameManager::getSharedData<float>("enemyRevealRadius");
        const float px = player->getTransform()->x + (player->getTexture() ? player->getTexture()->getWidth() * player->getTransform()->adjustedScaleX() / 2.f : 0.f);
        const float py = player->getTransform()->y + (player->getTexture() ? player->getTexture()->getHeight() * player->getTransform()->adjustedScaleY() / 2.f : 0.f);
        const float ew = getTexture() ? getTexture()->getWidth() * mTransform.adjustedScaleX() : 0.f;
        const float eh = getTexture() ? getTexture()->getHeight() * mTransform.adjustedScaleY() : 0.f;
        const float ex = mTransform.x + ew / 2.f;
        const float ey = mTransform.y + eh / 2.f;
        const float dxv = px - ex;
        const float dyv = py - ey;
        mIsVisible = (dxv * dxv + dyv * dyv) <= (revealRadius * revealRadius);
        
        // Semi-random movement with periodic direction changes
        mDirectionChangeTimer += deltaTime;
        if (mDirectionChangeTimer > 2.0f) {
            const float angle = static_cast<float>(Utils::getUtils().rirng32(0, 360)) * 3.14159f / 180.f;
            const float speed = 20.f + static_cast<float>(Utils::getUtils().rirng32(0, 30));
            mMoveSpeedX = std::cos(angle) * speed;
            mMoveSpeedY = std::sin(angle) * speed;
            mDirectionChangeTimer = 0.f;
        }
        
        // Move enemy
        mTransform.x += mMoveSpeedX * deltaTime;
        mTransform.y += mMoveSpeedY * deltaTime;

        // Decrease shoreline-spawn cooldown
        if (mShoreSpawnCooldown > 0.f) mShoreSpawnCooldown = std::max(0.f, mShoreSpawnCooldown - deltaTime);
        
        // Clamp to land section
        const float landBoundaryX = GameManager::getSharedData<float>("terrainLandBoundaryX");
        const float entityWidth = getTexture() ? getTexture()->getWidth() * mTransform.adjustedScaleX() : 0.f;
        const float entityHeight = getTexture() ? getTexture()->getHeight() * mTransform.adjustedScaleY() : 0.f;
        const float halfWidth = entityWidth / 2.f;
        const float halfHeight = entityHeight / 2.f;
        
        // Get window dimensions for boundary calculations
        int w = 0, h = 0;
        SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &w, &h);
        const float leftEdge = -w / 2.f + 25.f;
        
        if (mTransform.x - halfWidth < leftEdge) {
            mTransform.x = leftEdge + halfWidth;
            mMoveSpeedX = std::abs(mMoveSpeedX);
        }
        if (mTransform.x + halfWidth > landBoundaryX - 25.f) {
            mTransform.x = landBoundaryX - 25.f - halfWidth;
            mMoveSpeedX = -std::abs(mMoveSpeedX);

            // Enemy hit the shoreline on the right side; spawn a trash on the sea side
            if (mShoreSpawnCooldown <= 0.f) {
                auto* bg = GameManager::getEntityByName<AGame::Background>("BG");
                if (bg) {
                    Object::Transform t;
                    t.rotation = 0.f;
                    t.scaleX = 5.5f;
                    t.scaleY = 5.5f;
                    // Place trash on sea side at same Y
                    t.y = mTransform.y;
                    t.x = landBoundaryX + 10.f; // will be adjusted inside spawnTrashAt
                    bg->spawnTrashAt(t, true);
                }
                mShoreSpawnCooldown = 3.0f; // 3 second cooldown per enemy
            }
        }
        if (mTransform.y - halfHeight < -h / 2.f + 25.f) {
            mTransform.y = -h / 2.f + 25.f + halfHeight;
            mMoveSpeedY = std::abs(mMoveSpeedY);
        }
        if (mTransform.y + halfHeight > h / 2.f - 25.f) {
            mTransform.y = h / 2.f - 25.f - halfHeight;
            mMoveSpeedY = -std::abs(mMoveSpeedY);
        }
    }

    bool Enemy::hasAdjacentEnemy() {
        if (!getTexture()) return false;

        const float detectionRadius = 40.f;
        const float enemyWidth = getTexture()->getWidth() * mTransform.adjustedScaleX();
        const float enemyHeight = getTexture()->getHeight() * mTransform.adjustedScaleY();
        const float centerX = mTransform.x + enemyWidth / 2.f;
        const float centerY = mTransform.y + enemyHeight / 2.f;

        auto entities = GameManager::getEntityByName<Object::Entity>("Dummy");
        if (!entities) {
            auto snapshot = State::GameState::getInstance().getEntitiesSnapshot();
            for (auto* other : snapshot) {
                if (!other || other == this || !dynamic_cast<Enemy*>(other)) continue;
                auto* otherEnemy = dynamic_cast<Enemy*>(other);
                if (!otherEnemy || !otherEnemy->getTexture()) continue;
                const float otherWidth = otherEnemy->getTexture()->getWidth() * otherEnemy->getTransform()->adjustedScaleX();
                const float otherHeight = otherEnemy->getTexture()->getHeight() * otherEnemy->getTransform()->adjustedScaleY();
                const float otherCenterX = otherEnemy->getTransform()->x + otherWidth / 2.f;
                const float otherCenterY = otherEnemy->getTransform()->y + otherHeight / 2.f;
                const float dx = centerX - otherCenterX;
                const float dy = centerY - otherCenterY;
                if (dx * dx + dy * dy <= detectionRadius * detectionRadius) {
                    return true;
                }
            }
        }
        return false;
    }

    void Enemy::onCollisionEnter(Object::Entity* other) {
        auto* player = dynamic_cast<Player*>(other);
        if (!player || !mIsVisible) {
            return;
        }

        if (hasAdjacentEnemy()) {
            LOG("Igralec je trčil v močno skupino onesnaževalcev; konec igre!");
            GameManager::setSharedData("gameLost", true);
            GameManager::destroyEntity(player);
            return;
        }

        LOG("Sovražnik '" << getName() << "' je trčil v igralca; odstranjujem onesnaževalca in dodeljujem točke");
        GameManager::setSharedData("enemyActiveCount", std::max(0, GameManager::getSharedData<int>("enemyActiveCount") - 1));
        GameManager::setSharedData("gameScore", GameManager::getSharedData<int>("gameScore") + 100);
        GameManager::destroyEntity(this);
    }
}