#pragma once

#include <frostbite2D/2d/actor.h>
#include <frostbite2D/2d/sprite.h>
#include <frostbite2D/animation/animation_data.h>
#include <functional>
#include <string>
#include <vector>
#include <unordered_map>

namespace frostbite2D {

class Sprite;

class Animation : public Actor {
public:
  struct ReplaceData {
    int param1 = 0;
    int param2 = 0;
    ReplaceData() = default;
    ReplaceData(int p1, int p2) : param1(p1), param2(p2) {}
  };

public:
  Animation();
  explicit Animation(const std::string& aniPath);
  Animation(const std::string& aniPath,
            std::function<std::string(std::string, ReplaceData)> additionalOptions,
            ReplaceData data);
  ~Animation();

  void Init(const std::string& aniPath);

  void OnUpdate(float deltaTime) override;
  void OnAdded(Actor* parent) override;
  void SetVisible(bool visible);

public:
  void FlushFrame(int index);
  void Reset();
  animation::AniFrame GetCurrentFrameInfo() const;
  void SetFrameIndex(int index);
  void SetDirection(int direction);
  void InterpolationLogic();

  Vec2 GetMaxSize() const;
  bool GetStaticLocalBounds(Rect& outBounds) const;
  bool GetStaticLocalBounds(int direction, Rect& outBounds) const;
  uint64 GetRenderSignature() const;

  bool IsUsable() const { return usable_; }
  void SetUsable(bool usable) { usable_ = usable; }

  int GetCurrentFrameIndex() const { return currentFrameIndex_; }
  int GetTotalFrameCount() const { return totalFrameCount_; }

public:
  bool usable_ = true;
  int currentFrameIndex_ = 0;
  int totalFrameCount_ = 0;
  float currentFrameTime_ = 0.0f;
  Ptr<Sprite> currentFrame_ = nullptr;
  float nextFrameDelay_ = 9999999.0f;

  bool isLooping_ = true;

  std::function<void(int)> changeFrameCallback_;
  std::function<void()> endCallback_;

  std::vector<animation::AniFrame> frames_;
  std::vector<Ptr<Sprite>> spriteFrames_;
  std::vector<Vec2> spriteFrameOffsets_;

  std::unordered_map<std::string, animation::AniFlag> animationFlag_;

  std::string type_ = "normal";
  std::string aniPath_;

  std::function<std::string(std::string, ReplaceData)> additionalOptions_;
  ReplaceData additionalOptionsData_;

  Vec2 maxSize_ = Vec2::Zero();
  int direction_ = 1;

  std::vector<animation::AniFrame> interpolationData_;

private:
  void ApplyFramePresentation(const Vec2& framePos,
                              const Vec2& imageRate,
                              float rotation,
                              BlendMode blendMode);
};

} // namespace frostbite2D
