#pragma once

#include <glm/vec2.hpp>

#include <cstddef>
#include <cstdint>
#include <expected>
#include <filesystem>
#include <string_view>
#include <vector>

namespace kuiper
{

namespace resource
{

    struct image_error {
        std::string_view message;
    };

    class image {
      public:
        image(std::uint32_t       width,
              std::uint32_t       height,
              std::uint32_t       n_channels,
              const std::uint8_t* data,
              std::size_t         len)
            : m_width(width), m_height(height), m_channels(n_channels), m_data(data, data + len) {}
        image()                                  = default;
        ~image()                                 = default;
        image(const image& other)                = default;
        image& operator=(const image& other)     = default;
        image(image&& other) noexcept            = default;
        image& operator=(image&& other) noexcept = default;

        static image make_blank(std::uint32_t width, std::uint32_t height, std::uint32_t n_channels) noexcept;
        static std::expected<image, image_error> from_path(const std::filesystem::path& path,
                                                           std::uint8_t                 num_channels = 4) noexcept;
        static std::expected<image, image_error> from_memory(const std::uint8_t* data,
                                                             std::size_t         len,
                                                             std::uint8_t        num_channels = 4) noexcept;

        std::uint32_t width() const noexcept {
            return m_width;
        }

        std::uint32_t height() const noexcept {
            return m_height;
        }

        glm::uvec2 dimensions() const noexcept {
            return {m_width, m_height};
        }

        std::uint32_t channels() const noexcept {
            return m_channels;
        }

        const std::vector<std::uint8_t>& pixel_data() const noexcept {
            return m_data;
        }

        std::vector<std::uint8_t>& pixel_data_mut() noexcept {
            return m_data;
        }

        void resize(std::uint32_t width, std::uint32_t height) noexcept;

      private:
        std::uint32_t             m_width {0};
        std::uint32_t             m_height {0};
        std::uint32_t             m_channels {0};
        std::vector<std::uint8_t> m_data {};
    };

} // namespace resource

} // namespace kuiper
