/**
 * MaNGOS is a full featured server for World of Warcraft, supporting
 * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
 *
 * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * World of Warcraft, and all World of Warcraft or Warcraft art, images,
 * and lore are copyrighted by Blizzard Entertainment, Inc.
 */

#ifndef MANGOS_H_BATTLEGROUNDAV
#define MANGOS_H_BATTLEGROUNDAV

#include "Common.h"
#include "BattleGround.h"

#define BG_AV_MAX_NODE_DISTANCE             25              // distance in which players are still counted in range of a banner (for alliance towers this is calculated from the center of the tower)

#define BG_AV_BOSS_KILL_QUEST_SPELL         23658

#define BG_AV_CAPTIME                       240000          // 4 minutes
#define BG_AV_SNOWFALL_FIRSTCAP             300000          // 5 minutes but i also have seen 4:05

#define BG_AV_SCORE_INITIAL_POINTS          600
#define BG_AV_SCORE_NEAR_LOSE               120

// description: KILL = bonushonor kill one kill is 21honor worth at 0
// REP reputation, RES = ressources a team will lose
#define BG_AV_KILL_BOSS                     4
#define BG_AV_REP_BOSS                      350
#define BG_AV_REP_BOSS_HOLIDAY              525

#define BG_AV_KILL_CAPTAIN                  3
#define BG_AV_REP_CAPTAIN                   125
#define BG_AV_REP_CAPTAIN_HOLIDAY           185
#define BG_AV_RES_CAPTAIN                   100

#define BG_AV_KILL_TOWER                    3
#define BG_AV_REP_TOWER                     12
#define BG_AV_REP_TOWER_HOLIDAY             18
#define BG_AV_RES_TOWER                     75

#define BG_AV_KILL_GET_COMMANDER            1               // for a safely returned wingcommander TODO implement it

// bonushonor at the end
#define BG_AV_KILL_SURVIVING_TOWER          2
#define BG_AV_REP_SURVIVING_TOWER           12
#define BG_AV_REP_SURVIVING_TOWER_HOLIDAY   18

#define BG_AV_KILL_SURVIVING_CAPTAIN        2
#define BG_AV_REP_SURVIVING_CAPTAIN         125
#define BG_AV_REP_SURVIVING_CAPTAIN_HOLIDAY 175

#define BG_AV_KILL_MAP_COMPLETE             0
#define BG_AV_KILL_MAP_COMPLETE_HOLIDAY     4

#define BG_AV_REP_OWNED_GRAVE               12
#define BG_AV_REP_OWNED_GRAVE_HOLIDAY       18

#define BG_AV_REP_OWNED_MINE                24
#define BG_AV_REP_OWNED_MINE_HOLIDAY        36

/**
 * @brief
 *
 */
enum BG_AV_Sounds
{
    BG_AV_SOUND_NEAR_LOSE               = 8456,             // not confirmed yet

    BG_AV_SOUND_ALLIANCE_ASSAULTS       = 8212,             // tower,grave + enemy boss if someone tries to attack him
    BG_AV_SOUND_HORDE_ASSAULTS          = 8174,
    BG_AV_SOUND_ALLIANCE_GOOD           = 8173,             // if something good happens for the team:  wins(maybe only through killing the boss), captures mine or grave, destroys tower and defends grave
    BG_AV_SOUND_HORDE_GOOD              = 8213,
    BG_AV_SOUND_BOTH_TOWER_DEFEND       = 8192,

    BG_AV_SOUND_ALLIANCE_CAPTAIN        = 8232,             // gets called when someone attacks them and at the beginning after 3min + rand(x) * 10sec (maybe buff)
    BG_AV_SOUND_HORDE_CAPTAIN           = 8333
};

/**
 * @brief
 *
 */
enum BG_AV_OTHER_VALUES
{
    BG_AV_NORTH_MINE            = 0,
    BG_AV_SOUTH_MINE            = 1,
    BG_AV_MINE_TICK_TIMER       = 45000,
    BG_AV_MINE_RECLAIM_TIMER    = 1200000,                  // TODO: get the right value.. this is currently 20 minutes
    BG_AV_FACTION_A             = 730,
    BG_AV_FACTION_H             = 729
};
#define BG_AV_MAX_MINES 2

/**
 * @brief
 *
 */
enum BG_AV_ObjectIds
{
    // mine supplies
    BG_AV_OBJECTID_MINE_N               = 178785,
    BG_AV_OBJECTID_MINE_S               = 178784
};

/**
 * @brief
 *
 */
enum BG_AV_Nodes
{
    BG_AV_NODES_FIRSTAID_STATION        = 0,
    BG_AV_NODES_STORMPIKE_GRAVE         = 1,
    BG_AV_NODES_STONEHEART_GRAVE        = 2,
    BG_AV_NODES_SNOWFALL_GRAVE          = 3,
    BG_AV_NODES_ICEBLOOD_GRAVE          = 4,
    BG_AV_NODES_FROSTWOLF_GRAVE         = 5,
    BG_AV_NODES_FROSTWOLF_HUT           = 6,
    BG_AV_NODES_DUNBALDAR_SOUTH         = 7,
    BG_AV_NODES_DUNBALDAR_NORTH         = 8,
    BG_AV_NODES_ICEWING_BUNKER          = 9,
    BG_AV_NODES_STONEHEART_BUNKER       = 10,
    BG_AV_NODES_ICEBLOOD_TOWER          = 11,
    BG_AV_NODES_TOWER_POINT             = 12,
    BG_AV_NODES_FROSTWOLF_ETOWER        = 13,
    BG_AV_NODES_FROSTWOLF_WTOWER        = 14,
    BG_AV_NODES_ERROR                   = 255
};
#define BG_AV_NODES_MAX                 15

// for nodeevents we will use event1=node
// event2 is related to BG_AV_States
// 0 = alliance assaulted
// 1 = alliance control
// 2 = horde assaulted
// 3 = horde control
// 4 = neutral assaulted
// 5 = neutral control

// graves have special creatures - their defenders can be in 4 different states
// through some quests with armor scraps
// so i use event1=BG_AV_NODES_MAX+node (15-21)
// and event2=type

#define BG_AV_MINE_BOSSES       46                          // + mineid will be exact event
#define BG_AV_MINE_BOSSES_NORTH 46
#define BG_AV_MINE_BOSSES_SOUTH 47
#define BG_AV_CAPTAIN_A         48
#define BG_AV_CAPTAIN_H         49
#define BG_AV_MINE_EVENT        50                          // + mineid will be exact event
#define BG_AV_MINE_EVENT_NORTH  50
#define BG_AV_MINE_EVENT_SOUTH  51

#define BG_AV_MARSHAL_A_SOUTH   52
#define BG_AV_MARSHAL_A_NORTH   53
#define BG_AV_MARSHAL_A_ICE     54
#define BG_AV_MARSHAL_A_STONE   55
#define BG_AV_MARSHAL_H_ICE     56
#define BG_AV_MARSHAL_H_TOWER   57
#define BG_AV_MARSHAL_H_ETOWER  58
#define BG_AV_MARSHAL_H_WTOWER  59

#define BG_AV_HERALD            60
#define BG_AV_BOSS_A            61
#define BG_AV_BOSS_H            62
#define BG_AV_NodeEventCaptainDead_A 63
#define BG_AV_NodeEventCaptainDead_H 64

/**
 * @brief
 *
 */
enum BG_AV_Graveyards
{
    BG_AV_GRAVE_STORM_AID          = 751,
    BG_AV_GRAVE_STORM_GRAVE        = 689,
    BG_AV_GRAVE_STONE_GRAVE        = 729,
    BG_AV_GRAVE_SNOWFALL           = 169,
    BG_AV_GRAVE_ICE_GRAVE          = 749,
    BG_AV_GRAVE_FROSTWOLF          = 690,
    BG_AV_GRAVE_FROST_HUT          = 750,
    BG_AV_GRAVE_MAIN_ALLIANCE      = 611,
    BG_AV_GRAVE_MAIN_HORDE         = 610
};

const uint32 BG_AV_GraveyardIds[9] = /**< TODO */
{
    BG_AV_GRAVE_STORM_AID,
    BG_AV_GRAVE_STORM_GRAVE,
    BG_AV_GRAVE_STONE_GRAVE,
    BG_AV_GRAVE_SNOWFALL,
    BG_AV_GRAVE_ICE_GRAVE,
    BG_AV_GRAVE_FROSTWOLF,
    BG_AV_GRAVE_FROST_HUT,
    BG_AV_GRAVE_MAIN_ALLIANCE,
    BG_AV_GRAVE_MAIN_HORDE
};

/**
 * @brief
 *
 */
enum BG_AV_States
{
    POINT_ASSAULTED             = 0,
    POINT_CONTROLLED            = 1
};
#define BG_AV_MAX_STATES 2

/**
 * @brief
 *
 */
enum BG_AV_WorldStates
{
    BG_AV_Alliance_Score        = 3127,
    BG_AV_Horde_Score           = 3128,
    BG_AV_SHOW_H_SCORE          = 3133,
    BG_AV_SHOW_A_SCORE          = 3134,
    AV_SNOWFALL_N               = 1966
};

/**
 * @brief special version with  more wide values range that BattleGroundTeamIndex
 *
 * BattleGroundAVTeamIndex <- BattleGroundTeamIndex cast safe
 * BattleGroundAVTeamIndex -> BattleGroundTeamIndex cast safe and array with BG_TEAMS_COUNT elements must checked != BG_AV_TEAM_NEUTRAL before used
 *
 */
enum BattleGroundAVTeamIndex
{
    BG_AV_TEAM_ALLIANCE        = TEAM_INDEX_ALLIANCE,
    BG_AV_TEAM_HORDE           = TEAM_INDEX_HORDE,
    BG_AV_TEAM_NEUTRAL         = TEAM_INDEX_NEUTRAL,                         // this is the neutral owner of snowfall
};

#define BG_AV_TEAMS_COUNT 3

const uint32 BG_AV_MineWorldStates[2][BG_AV_TEAMS_COUNT] = /**< alliance_control horde_control neutral_control */
{
    {1358, 1359, 1360},
    {1355, 1356, 1357}
};

const uint32 BG_AV_NodeWorldStates[BG_AV_NODES_MAX][4] = /**< alliance_control alliance_assault h_control h_assault */
{
    // Stormpike first aid station
    {1326, 1325, 1328, 1327},
    // Stormpike Graveyard
    {1335, 1333, 1336, 1334},
    // Stoneheart Grave
    {1304, 1302, 1303, 1301},
    // Snowfall Grave
    {1343, 1341, 1344, 1342},
    // Iceblood grave
    {1348, 1346, 1349, 1347},
    // Frostwolf Grave
    {1339, 1337, 1340, 1338},
    // Frostwolf Hut
    {1331, 1329, 1332, 1330},
    // Dunbaldar South Bunker
    {1375, 1361, 1378, 1370},
    // Dunbaldar North Bunker
    {1374, 1362, 1379, 1371},
    // Icewing Bunker
    {1376, 1363, 1380, 1372},
    // Stoneheart Bunker
    {1377, 1364, 1381, 1373},
    // Iceblood Tower
    {1390, 1368, 1395, 1385},
    // Tower Point
    {1389, 1367, 1394, 1384},
    // Frostwolf East
    {1388, 1366, 1393, 1383},
    // Frostwolf West
    {1387, 1365, 1392, 1382},
};

#define BG_AV_MAX_GRAVETYPES 4
/**
 * @brief through the armorscap-quest 4 different gravedefender exist
 *
 */
enum BG_AV_QuestIds
{
    BG_AV_QUEST_A_SCRAPS1       = 7223,                     // first quest
    BG_AV_QUEST_A_SCRAPS2       = 6781,                     // repeatable
    BG_AV_QUEST_H_SCRAPS1       = 7224,
    BG_AV_QUEST_H_SCRAPS2       = 6741,
    BG_AV_QUEST_A_COMMANDER1    = 6942,                     // soldier
    BG_AV_QUEST_H_COMMANDER1    = 6825,
    BG_AV_QUEST_A_COMMANDER2    = 6941,                     // leutnant
    BG_AV_QUEST_H_COMMANDER2    = 6826,
    BG_AV_QUEST_A_COMMANDER3    = 6943,                     // commander
    BG_AV_QUEST_H_COMMANDER3    = 6827,
    BG_AV_QUEST_A_BOSS1         = 7386,                     // 5 cristal/blood
    BG_AV_QUEST_H_BOSS1         = 7385,
    BG_AV_QUEST_A_BOSS2         = 6881,                     // 1
    BG_AV_QUEST_H_BOSS2         = 6801,
    BG_AV_QUEST_A_NEAR_MINE     = 5892,                     // the mine near start location of team
    BG_AV_QUEST_H_NEAR_MINE     = 5893,
    BG_AV_QUEST_A_OTHER_MINE    = 6982,                     // the other mine ;)
    BG_AV_QUEST_H_OTHER_MINE    = 6985,
    BG_AV_QUEST_A_RIDER_HIDE    = 7026,
    BG_AV_QUEST_H_RIDER_HIDE    = 7002,
    BG_AV_QUEST_A_RIDER_TAME    = 7027,
    BG_AV_QUEST_H_RIDER_TAME    = 7001
};

/**
 * @brief
 *
 */
struct BG_AV_NodeInfo
{
    BattleGroundAVTeamIndex TotalOwner; /**< TODO */
    BattleGroundAVTeamIndex Owner; /**< TODO */
    BattleGroundAVTeamIndex PrevOwner; /**< TODO */
    BG_AV_States State; /**< TODO */
    BG_AV_States PrevState; /**< TODO */
    uint32       Timer; /**< TODO */
    bool         Tower; /**< TODO */
};

/**
 * @brief
 *
 * @param i
 * @return BG_AV_Nodes &operator
 */
inline BG_AV_Nodes& operator++(BG_AV_Nodes& i)
{
    return i = BG_AV_Nodes(i + 1);
}

/**
 * @brief
 *
 */
class BattleGroundAVScore : public BattleGroundScore
{
    public:
/**
 * @brief
 *
 */
        BattleGroundAVScore() : GraveyardsAssaulted(0), GraveyardsDefended(0), TowersAssaulted(0), TowersDefended(0), SecondaryObjectives(0), LieutnantCount(0), SecondaryNPC(0) {};
        /**
         * @brief
         *
         */
        virtual ~BattleGroundAVScore() {};

        uint32 GetAttr1() const { return GraveyardsAssaulted; }
        uint32 GetAttr2() const { return GraveyardsDefended; }
        uint32 GetAttr3() const { return TowersAssaulted; }
        uint32 GetAttr4() const { return TowersDefended; }
        uint32 GetAttr5() const { return SecondaryObjectives; }

        uint32 GraveyardsAssaulted; /**< TODO */
        uint32 GraveyardsDefended; /**< TODO */
        uint32 TowersAssaulted; /**< TODO */
        uint32 TowersDefended; /**< TODO */
        uint32 SecondaryObjectives; /**< TODO */
        uint32 LieutnantCount; /**< TODO */
        uint32 SecondaryNPC; /**< TODO */
};

/**
 * @brief
 *
 */
class BattleGroundAV : public BattleGround
{
        friend class BattleGroundMgr;

    public:
        /**
         * @brief
         *
         */
        BattleGroundAV();
        /**
         * @brief
         *
         * @param diff
         */
        void Update(uint32 diff) override;

        /**
         * @brief inherited from BattlegroundClass
         *
         * @param plr
         */
        virtual void AddPlayer(Player* plr) override;

        /**
         * @brief
         *
         */
        virtual void StartingEventOpenDoors() override;
        /**
         * @brief  world states
         *
         * @param data
         * @param count
         */
        virtual void FillInitialWorldStates(WorldPacket& data, uint32& count) override;

        /**
         * @brief
         *
         * @param source
         * @param trigger
         */
        bool HandleAreaTrigger(Player* source, uint32 trigger) override;
        /**
         * @brief
         *
         */
        virtual void Reset() override;

        /*general stuff*/
        /**
         * @brief
         *
         * @param teamIdx
         * @param points
         */
        void UpdateScore(PvpTeamIndex teamIdx, int32 points);
        /**
         * @brief
         *
         * @param source
         * @param type
         * @param value
         */
        void UpdatePlayerScore(Player* source, uint32 type, uint32 value) override;

        /*handle stuff*/ // these are functions which get called from extern scripts
        /**
         * @brief
         *
         * @param source
         * @param target_obj
         */
        virtual void EventPlayerClickedOnFlag(Player* source, GameObject* target_obj) override;
        /**
         * @brief
         *
         * @param player
         * @param killer
         */
        void HandleKillPlayer(Player* player, Player* killer) override;
        /**
         * @brief
         *
         * @param creature
         * @param killer
         */
        void HandleKillUnit(Creature* creature, Player* killer) override;
        /**
         * @brief
         *
         * @param questid
         * @param player
         */
        void HandleQuestComplete(uint32 questid, Player* player);
        /**
         * @brief
         *
         * @param GOId
         * @param team
         * @return bool
         */
        bool PlayerCanDoMineQuest(int32 GOId, Team team);

        /**
         * @brief
         *
         * @param winner
         */
        void EndBattleGround(Team winner) override;

        /**
         * @brief
         *
         * @param plr
         * @return const WorldSafeLocsEntry
         */
        virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* plr) override;

        /**
         * @brief
         *
         * @return Team
         */
        virtual Team GetPrematureWinner() override;

        /**
         * @brief
         *
         * @param team
         * @return BattleGroundAVTeamIndex
         */
        static BattleGroundAVTeamIndex GetAVTeamIndexByTeamId(Team team) { return BattleGroundAVTeamIndex(GetTeamIndexByTeamId(team)); }
    private:
        /* Nodes occupying */
        /**
         * @brief
         *
         * @param player
         * @param node
         */
        void EventPlayerAssaultsPoint(Player* player, BG_AV_Nodes node);
        /**
         * @brief
         *
         * @param player
         * @param node
         */
        void EventPlayerDefendsPoint(Player* player, BG_AV_Nodes node);
        /**
         * @brief
         *
         * @param node
         */
        void EventPlayerDestroyedPoint(BG_AV_Nodes node);

        /**
         * @brief
         *
         * @param node
         * @param teamIdx
         */
        void AssaultNode(BG_AV_Nodes node, PvpTeamIndex teamIdx);
        /**
         * @brief
         *
         * @param node
         */
        void DestroyNode(BG_AV_Nodes node);
        /**
         * @brief
         *
         * @param node
         * @param teamIdx
         * @param tower
         */
        void InitNode(BG_AV_Nodes node, BattleGroundAVTeamIndex teamIdx, bool tower);
        /**
         * @brief
         *
         * @param node
         * @param teamIdx
         */
        void DefendNode(BG_AV_Nodes node, PvpTeamIndex teamIdx);

        /**
         * @brief
         *
         * @param node
         */
        void PopulateNode(BG_AV_Nodes node);

        /**
         * @brief
         *
         * @param node
         * @return uint32
         */
        uint32 GetNodeName(BG_AV_Nodes node) const;
        /**
         * @brief
         *
         * @param node
         * @return bool
         */
        bool IsTower(BG_AV_Nodes node) const { return (node == BG_AV_NODES_ERROR) ? false : m_Nodes[node].Tower; }
        /**
         * @brief
         *
         * @param node
         * @return bool
         */
        bool IsGrave(BG_AV_Nodes node) const { return (node == BG_AV_NODES_ERROR) ? false : !m_Nodes[node].Tower; }

        /*mine*/
        /**
         * @brief
         *
         * @param mine
         * @param teamIdx
         */
        void ChangeMineOwner(uint8 mine, BattleGroundAVTeamIndex teamIdx);

        /*worldstates*/
        /**
         * @brief
         *
         * @param state
         * @param teamIdx
         * @return uint8
         */
        uint8 GetWorldStateType(uint8 state, BattleGroundAVTeamIndex teamIdx) const { return teamIdx * BG_AV_MAX_STATES + state; }
        /**
         * @brief
         *
         * @param mine
         */
        void SendMineWorldStates(uint32 mine);
        /**
         * @brief
         *
         * @param node
         */
        void UpdateNodeWorldState(BG_AV_Nodes node);

        /*variables */
        uint32 m_Team_QuestStatus[PVP_TEAM_COUNT][9];       /**< [x][y] x=team y=questcounter */

        BG_AV_NodeInfo m_Nodes[BG_AV_NODES_MAX]; /**< TODO */

        // only for worldstates needed
        BattleGroundAVTeamIndex m_Mine_Owner[BG_AV_MAX_MINES]; /**< TODO */
        BattleGroundAVTeamIndex m_Mine_PrevOwner[BG_AV_MAX_MINES]; /**< TODO */
        int32 m_Mine_Timer[BG_AV_MAX_MINES]; /**< TODO */
        uint32 m_Mine_Reclaim_Timer[BG_AV_MAX_MINES]; /**< TODO */

        bool m_IsInformedNearLose[PVP_TEAM_COUNT]; /**< TODO */

        uint32 m_HonorMapComplete; /**< TODO */
        uint32 m_RepTowerDestruction; /**< TODO */
        uint32 m_RepCaptain; /**< TODO */
        uint32 m_RepBoss; /**< TODO */
        uint32 m_RepOwnedGrave; /**< TODO */
        uint32 m_RepOwnedMine; /**< TODO */
        uint32 m_RepSurviveCaptain; /**< TODO */
        uint32 m_RepSurviveTower; /**< TODO */
};

#endif
