#include "combat/boss_phase_controller.hpp"

namespace combat {

BossPhaseController::BossPhaseController(const BossPhaseConfig& config)
    : m_config(config) {
}

void BossPhaseController::SetArenaCenter(float centerX, float centerY) {
    m_info.arenaCenterX = centerX;
    m_info.arenaCenterY = centerY;
    m_hasExplicitCenter = true;
}

void BossPhaseController::Reset() {
    m_info = BossPhaseInfo{};
    m_hasExplicitCenter = false;
}

BossPhaseState BossPhaseController::UpdatePhase(const TelemetryPacket& packet,
                                               uint32_t activeBossId,
                                               uint64_t nowMs) {
    const EntityTelemetryData* bossEnt = nullptr;

    // 1. Tìm kiếm Boss trong Telemetry packet
    for (uint32_t i = 0; i < packet.entityCount; ++i) {
        const auto& ent = packet.entities[i];
        if (ent.type != 1) continue; // Chỉ quét monster

        // Khớp Boss theo activeBossId được chỉ định trước đó
        if (activeBossId != 0 && ent.id == activeBossId) {
            bossEnt = &ent;
            break;
        }

        // Hoặc nhận diện Boss qua bitmask extraFlags và độ hiếm
        const bool isBoss = (ent.extraFlags & game_layout::kEntityFlagBoss) != 0 || (ent.rarity >= 3);
        if (isBoss && !(ent.extraFlags & game_layout::kEntityFlagDead) && ent.currentHP > 0) {
            bossEnt = &ent;
            break;
        }
    }

    // 2. Xử lý khi tìm thấy Boss trên radar
    if (bossEnt != nullptr) {
        m_info.bossId = bossEnt->id;
        m_info.bossLastPosX = bossEnt->posX;
        m_info.bossLastPosY = bossEnt->posY;
        m_info.isBossOnRadar = true;

        // Nếu chưa có tâm sàn đấu cụ thể, tự động lấy vị trí ban đầu của Boss làm tâm
        if (!m_hasExplicitCenter) {
            m_info.arenaCenterX = bossEnt->posX;
            m_info.arenaCenterY = bossEnt->posY;
            m_hasExplicitCenter = true;
        }

        // Kiểm tra nếu Boss đã chết
        if ((bossEnt->extraFlags & game_layout::kEntityFlagDead) || bossEnt->currentHP == 0) {
            m_info.state = BossPhaseState::NoBoss;
            m_info.isInvulnerable = false;
            m_info.isTargetable = false;
            return m_info.state;
        }

        // Đánh giá trạng thái bất tử (Immunity / Untargetable Phase)
        const bool hasInvulnBit = (bossEnt->extraFlags & game_layout::kEntityFlagInvulnerable) != 0;
        const bool hasUntargetableBit = (bossEnt->extraFlags & game_layout::kEntityFlagUntargetable) != 0;
        const bool hasTargetableBit = (bossEnt->extraFlags & game_layout::kEntityFlagTargetable) != 0;

        if (hasTargetableBit) {
            m_info.hasSeenTargetable = true;
        }

        // Untargetable phase: khi có bit Untargetable, HOẶC khi đã từng thấy Targetable và nay bị mất cờ này
        const bool isUntargetable = hasUntargetableBit || (m_info.hasSeenTargetable && !hasTargetableBit);
        const bool isInvuln = hasInvulnBit || isUntargetable;

        if (isInvuln) {
            if (m_info.state != BossPhaseState::ImmunityPhase) {
                m_info.state = BossPhaseState::ImmunityPhase;
                m_info.phaseStartTimestampMs = nowMs;
            }
            m_info.isInvulnerable = true;
            m_info.isTargetable = !isUntargetable;
        } else {
            // Boss đang trong trạng thái dễ bị tổn thương (Vulnerable / Targetable)
            m_info.state = BossPhaseState::ActiveCombat;
            m_info.isInvulnerable = false;
            m_info.isTargetable = true;
        }

        return m_info.state;
    }

    // 3. Xử lý khi Boss biến mất khỏi radar (lặn / bay / triệu hồi)
    m_info.isBossOnRadar = false;

    if (m_info.state == BossPhaseState::ActiveCombat || m_info.state == BossPhaseState::ImmunityPhase) {
        // Boss vừa biến mất -> chuyển sang DisappearedPhase
        m_info.state = BossPhaseState::DisappearedPhase;
        m_info.phaseStartTimestampMs = nowMs;
        m_info.isInvulnerable = true;
        m_info.isTargetable = false;
    } else if (m_info.state == BossPhaseState::DisappearedPhase) {
        // Kiểm tra quá hạn thời gian pha lặn/bay
        if (m_config.phaseTimeoutMs > 0 && (nowMs - m_info.phaseStartTimestampMs > m_config.phaseTimeoutMs)) {
            m_info.state = BossPhaseState::NoBoss;
            m_info.isInvulnerable = false;
            m_info.isTargetable = false;
        }
    }

    return m_info.state;
}

OrbitalVector BossPhaseController::ComputeOrbitalKiteVector(float playerX, float playerY) const {
    OrbitalVector out{};

    // Vector bán kính từ tâm sàn đấu tới người chơi
    float rx = playerX - m_info.arenaCenterX;
    float ry = playerY - m_info.arenaCenterY;
    float dist = std::sqrt(rx * rx + ry * ry);

    if (dist < 0.001f) {
        // Người chơi đang đứng đúng tâm sàn đấu: chọn hướng mặc định sang phải
        rx = m_config.defaultOrbitalRadius;
        ry = 0.0f;
        dist = m_config.defaultOrbitalRadius;
    }

    const float invDist = 1.0f / dist;
    const float nrx = rx * invDist;
    const float nry = ry * invDist;

    // Vector tiếp tuyến vuông góc với bán kính
    // Thuận chiều kim đồng hồ (Clockwise): (x, y) -> (y, -x)
    // Ngược chiều kim đồng hồ (Counter-Clockwise): (x, y) -> (-y, x)
    float tx = 0.0f;
    float ty = 0.0f;
    if (m_config.clockwiseOrbit) {
        tx = nry;
        ty = -nrx;
    } else {
        tx = -nry;
        ty = nrx;
    }

    // Lực hiệu chỉnh bán kính (Radial Correction): giữ nhân vật di chuyển quanh defaultOrbitalRadius
    const float radialDelta = m_config.defaultOrbitalRadius - dist;
    const float radialWeight = std::clamp(radialDelta * m_config.radialCorrectionGain, -0.6f, 0.6f);

    // Vector di chuyển tổng hợp giữa tiếp tuyến và lực kéo/đẩy về bán kính chuẩn
    float moveDx = tx + nrx * radialWeight;
    float moveDy = ty + nry * radialWeight;

    const float moveLen = std::sqrt(moveDx * moveDx + moveDy * moveDy);
    if (moveLen > 0.001f) {
        const float invMoveLen = 1.0f / moveLen;
        moveDx *= invMoveLen;
        moveDy *= invMoveLen;
    }

    out.moveDx = moveDx;
    out.moveDy = moveDy;
    out.currentRadius = dist;
    out.currentAngleRad = std::atan2(ry, rx);

    return out;
}

} // namespace combat
