#pragma once

#include <frostbite2D/2d/actor.h>
#include <frostbite2D/graphics/texture.h>
#include <frostbite2D/graphics/shader.h>
#include <frostbite2D/graphics/types.h>
#include <string>

namespace frostbite2D {

class Sprite : public Actor {
public:
  Sprite();
  explicit Sprite(Ptr<Texture> texture);
  virtual ~Sprite();

  static Ptr<Sprite> createFromFile(const std::string& path);
  static Ptr<Sprite> createFromMemory(const uint8* data, int width, int height, int channels);
  static Ptr<Sprite> createFromNpk(const std::string& imgPath, size_t frameIndex = 0);

  void Render() override;

  void SetTexture(Ptr<Texture> texture);
  Ptr<Texture> GetTexture() const { return texture_; }

  void SetShader(const std::string& shaderName);
  void SetDefaultShader();
  const std::string& GetShaderName() const { return shaderName_; }
  bool HasCustomShader() const { return !shaderName_.empty(); }

  void SetSourceRect(const Rect& rect);
  const Rect& GetSourceRect() const { return srcRect_; }

  void SetColor(const Color& color);
  void SetColor(float r, float g, float b, float a = 1.0f);
  const Color& GetColor() const { return color_; }

  void SetFlippedX(bool flipped);
  void SetFlippedY(bool flipped);
  bool IsFlippedX() const { return flippedX_; }
  bool IsFlippedY() const { return flippedY_; }

  void SetBlendMode(BlendMode mode);
  BlendMode GetBlendMode() const { return blendMode_; }

  void SetSizeToTexture();

  const Vec2& GetOffset() const { return offset_; }
  void SetOffset(const Vec2& offset);
  void SetOffset(float x, float y);

private:
  void updateTransform();
  Shader* getActiveShader() const;
  Quad createQuad() const;

  Ptr<Texture> texture_;
  std::string shaderName_;
  Color color_ = Color(1.0f, 1.0f, 1.0f, 1.0f);
  Rect srcRect_;
  bool flippedX_ = false;
  bool flippedY_ = false;
  BlendMode blendMode_ = BlendMode::Normal;
  Vec2 offset_ = Vec2::Zero();
  Transform2D transform_;

  static constexpr const char* DEFAULT_SHADER = "sprite";
};

}

