#pragma once

#include "core/Core.hpp"
#include "NPCManager.hpp"
#include "Entities.hpp"

struct Mob : public CombatNPC {
    // general
    std::unordered_map<int32_t,time_t> unbuffTimes = {};

    // dead
    time_t killedTime = 0;
    time_t regenTime = 0;
    bool summoned = false;
    bool despawned = false; // for the sake of death animations

    // roaming
    int idleRange = 0;
    const int sightRange = 0;
    time_t nextMovement = 0;
    bool staticPath = false;
    int roamX = 0, roamY = 0, roamZ = 0;

    // combat
    CNSocket *target = nullptr;
    time_t nextAttack = 0;
    time_t lastDrainTime = 0;
    int skillStyle = -1; // -1 for nothing, 0-2 for corruption, -2 for eruption
    int hitX = 0, hitY = 0, hitZ = 0; // for use in ability targeting

    // group
    int groupLeader = 0;
    int offsetX = 0, offsetY = 0;
    int groupMember[4] = {};

    // temporary; until we're sure what's what
    nlohmann::json data = {};

    Mob(int x, int y, int z, int angle, uint64_t iID, int t, nlohmann::json d, int32_t id)
        : CombatNPC(x, y, z, angle, iID, t, id, d["m_iHP"]),
          sightRange(d["m_iSightRange"]) {
        state = AIState::ROAMING;

        data = d;

        speed = data["m_iRunSpeed"];
        regenTime = data["m_iRegenTime"];
        idleRange = (int)data["m_iIdleRange"];
        level = data["m_iNpcLevel"];

        roamX = x;
        roamY = y;
        roamZ = z;

        offsetX = 0;
        offsetY = 0;

        cbf = 0;

        // NOTE: there appear to be discrepancies in the dump
        hp = maxHealth;

        kind = EntityKind::MOB;
    }

    // constructor for /summon
    Mob(int x, int y, int z, uint64_t iID, int t, nlohmann::json d, int32_t id)
        : Mob(x, y, z, 0, iID, t, d, id) {
        summoned = true; // will be despawned and deallocated when killed
    }

    ~Mob() {}

    virtual void roamingStep(time_t currTime) override;
    virtual void combatStep(time_t currTime) override;
    virtual void retreatStep(time_t currTime) override;
    virtual void deadStep(time_t currTime) override;

    virtual void onInactive() override;
    virtual void onRoamStart() override;
    virtual void onCombatStart(EntityRef src) override;
    virtual void onRetreat() override;
    virtual void onDeath(EntityRef src) override;

    auto operator[](std::string s) {
        return data[s];
    }
};

namespace MobAI {
    extern bool simulateMobs;

    // TODO: make this internal later
    void incNextMovement(Mob *mob, time_t currTime=0);
    bool aggroCheck(Mob *mob, time_t currTime);
    void clearDebuff(Mob *mob);
    void followToCombat(Mob *mob);
    void groupRetreat(Mob *mob);
}