#pragma once

#define ORDERERSPRITESET typeid(OrdererSpriteSet).name()

#include "elements/BehaviourScript.hpp"
#include "elements/Transformable.hpp"
#include "Types.hpp"
#include "enums/SortingOrder.hpp"
#include "Vector2.hpp"
#include "Vector2i.hpp"
#include <unordered_map>
#include "elements/Sprite.hpp"
#include "elements/TileSet.hpp"

namespace TSE
{
    struct OrdererSpriteSetChunk
    {
    private:
        std::vector<Vector3> orderedPositions;
        std::vector<Vector2i> orderedSpriteIDs;
        std::vector<Vector2> orderedScales;
        SortingOrder order;
        int chunksize;
        std::unordered_map<Vector3, Vector2i> sprites;
        std::unordered_map<Vector3, Vector2> spriteScales;
    public:
        bool dirtyPositions = true;
        bool dirtySpriteIds = true;
        bool dirtyScales = true;
        Vector2 pos;

        OrdererSpriteSetChunk(int _chunksize = 16, const Vector2& _pos = {0,0}, SortingOrder _order = TopRight);
        void SetSprite(const Vector2& p, const Vector2& Spriteindex, const Vector2& Normalindex, TileSet* set, float height, Vector2& scale);
        void RemoveSprite(Vector2 p, float height);
        void SetOrdering(SortingOrder _order);
        const std::vector<Vector3>* GetOrderedPositions();
        const std::vector<Vector2i>* GetOrderedSpriteIds();
        const std::vector<Vector2>* GetOrderedScales();
        int GetChunksize();
        int GetSpriteCount();
    };
    
    
    class OrdererSpriteSet : public TSE::BehaviourScript
    {
    private:
        bool dirty = true;
        std::vector<Vector2> orderedChunks;
        Rect bounds = Rect(0,0,0,0);
        
    public:
        int chunkSize = 16;
        SortingOrder order = TopRight;
        TileSet* set;
        std::unordered_map<Vector2, OrdererSpriteSetChunk> chunks;
        
        void RemoveSprite(Vector2 p, float height);
        void SetSprite(Vector2 p, Vector2 Spriteindex, float height, Vector2 scale, Vector2 Normalindex = {-1,-1});
        OrdererSpriteSetChunk* GetChunk(const Vector2& pos);
        const std::vector<Vector2>* GetChunkPositionsInOrder();
        int GetChunkCount();
        TileSet* GetTileSet();
        void DirtyAll();

        inline const char* GetName() override
        {
            return "Orderer Sprite Set";
        }
    
    private:
        Vector2 LocalToChunkPos(const Vector2& v);
    };
} // namespace TSE