#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

#include "types.h"

namespace stb {
  class UniqueImage {
   public:
    // Constructor
    UniqueImage(const char* filename) { load(filename); }

    // Deleted copy constructor and assignment operator
    UniqueImage(const UniqueImage&)                = delete;
    fn operator=(const UniqueImage&)->UniqueImage& = delete;

    // Move constructor and assignment operator
    UniqueImage(UniqueImage&& other) noexcept
      : mData(other.mData), mWidth(other.mWidth), mHeight(other.mHeight), mChannels(other.mChannels) {
      other.mData = nullptr; // Set the other's data to nullptr
    }

    fn operator=(UniqueImage&& other) noexcept -> UniqueImage& {
      if (this != &other) {
        // Free existing resource
        if (mData)
          stbi_image_free(mData);

        // Move the resource
        mData       = other.mData;
        mWidth      = other.mWidth;
        mHeight     = other.mHeight;
        mChannels   = other.mChannels;
        other.mData = nullptr; // Set the other's data to nullptr
      }
      return *this;
    }

    // Destructor
    ~UniqueImage() {
      if (mData)
        stbi_image_free(mData);
    }

    // Accessors for image data and dimensions
    [[nodiscard]] fn getData() const -> unsigned char* { return mData; }

    [[nodiscard]] fn getWidth() const -> int { return mWidth; }

    [[nodiscard]] fn getHeight() const -> int { return mHeight; }

    [[nodiscard]] fn getChannels() const -> int { return mChannels; }

   private:
    unsigned char* mData     = nullptr;
    int            mWidth    = 0;
    int            mHeight   = 0;
    int            mChannels = 0;

    // Load function
    void load(const char* filename) {
      mData = stbi_load(filename, &mWidth, &mHeight, &mChannels, STBI_rgb_alpha);

      if (!mData)
        throw std::runtime_error("Failed to load image: " + std::string(stbi_failure_reason()));
    }
  };
}
