#pragma once
#include <cstdint>
#include <Eigen/Eigen>

template<typename From, typename To>
To convert(const From& value) {
    // 如果源和目标类型相同，直接返回
    if constexpr (std::is_same_v<From, To>) {
        return value;
    }

    // 获取 From 类型的最小值和最大值
    const auto source_min = static_cast<double>(std::numeric_limits<From>::lowest());
    const auto source_max = static_cast<double>(std::numeric_limits<From>::max());

    // 获取 To 类型的最小值和最大值
    const auto target_min = static_cast<double>(std::numeric_limits<To>::lowest());
    const auto target_max = static_cast<double>(std::numeric_limits<To>::max());

    // 线性映射公式
    auto normalized = (static_cast<double>(value) - source_min) / (source_max - source_min); // [0, 1]
    return static_cast<To>(target_min + normalized * (target_max - target_min));
}

template<typename From, typename To>
To color_convert(const From& value) {
    // 如果源和目标类型相同，直接返回
    if constexpr (std::is_same_v<From, To>) {
        return value;
    }

    // 如果源和目标都是整数，使用整数到整数的转换
    if constexpr (std::is_integral_v<From> && std::is_integral_v<To>) {
        return convert<From, To>(value);
    }

    // 如果是整数到浮点数的映射
    if constexpr (std::is_integral_v<From> && std::is_floating_point_v<To>) {
        const auto source_min = static_cast<double>(std::numeric_limits<From>::lowest()); // 整数最小值
        const auto source_max = static_cast<double>(std::numeric_limits<From>::max());    // 整数最大值

        // 将整数值映射到 [0, 1] 区间
        double normalized = (static_cast<double>(value) - source_min) / (source_max - source_min);
        return static_cast<To>(normalized); // 映射到浮点数
    }

    // 如果是浮点数到整数的映射
    if constexpr (std::is_floating_point_v<From> && std::is_integral_v<To>) {
        const auto target_min = static_cast<double>(std::numeric_limits<To>::lowest()); // 整数最小值
        const auto target_max = static_cast<double>(std::numeric_limits<To>::max());    // 整数最大值

        // 将浮点数从 [0, 1] 的区间映射到目标整数范围
        double clamped = std::clamp(static_cast<double>(value), 0.0, 1.0); // 限制到 [0, 1]
        return static_cast<To>(target_min + clamped * (target_max - target_min));
    }

    // 如果是浮点数到浮点数的映射
    if constexpr (std::is_floating_point_v<From> && std::is_floating_point_v<To>) {
        const auto source_min = static_cast<double>(std::numeric_limits<From>::lowest());
        const auto source_max = static_cast<double>(std::numeric_limits<From>::max());

        const auto target_min = static_cast<double>(std::numeric_limits<To>::lowest());
        const auto target_max = static_cast<double>(std::numeric_limits<To>::max());

        // 线性映射
        double normalized = (static_cast<double>(value) - source_min) / (source_max - source_min); // [0, 1]
        return static_cast<To>(target_min + normalized * (target_max - target_min));
    }

    // 默认情况（应该不会触发）
    return static_cast<To>(value);
}

template<typename T, int N>
struct pixel {
    using pixel_type = T;

    pixel() = default;
    pixel(const pixel& rhs) {
        for (int i = 0; i < N; i++) {
            data[i] = rhs.data[i];
        }
    }
    // 从不同类型的像素转换
    template<typename U, int N2>
    pixel(const pixel<U, N2>& rhs) {
        *this = rhs;
    }

    T data[N];
    T& operator[](int i) { return data[i]; }

    T& r() { return data[0]; }
    T& g() { return data[1]; }
    T& b() { return data[2]; }
    T& a() { return data[3]; }

    T r() const { return data[0]; }
    T g() const { return data[1]; }
    T b() const { return data[2]; }
    T a() const { return data[3]; }

    // 转换为亮度
    T luminance() const {
        return 0.2126f * data[0] + 0.7152f * data[1] + 0.0722f * data[2];
    }
    // 转换为灰度
    T grayscale() const {
        return (data[0] + data[1] + data[2]) / 3;
    }
    // 转换为sRGB
    T sRGB() const {
        return data[0] <= 0.0031308f ? 12.92f * data[0] : 1.055f * pow(data[0], 1.0f / 2.4f) - 0.055f;
    }
    // 转换为线性RGB
    T linearRGB() const {
        return data[0] <= 0.04045f ? data[0] / 12.92f : pow((data[0] + 0.055f) / 1.055f, 2.4f);
    }
    // 转换为YCbCr
    T YCbCr() const {
        return 0.299f * data[0] + 0.587f * data[1] + 0.114f * data[2];
    }
    // 转换为YUV
    T YUV() const {
        return 0.299f * data[0] + 0.587f * data[1] + 0.114f * data[2];
    }

    T operator+(const pixel& rhs) const {
        pixel result;
        for (int i = 0; i < N; ++i) {
            result.data[i] = data[i] + rhs.data[i];
        }
        return result;
    }
    T operator-(const pixel& rhs) const {
        pixel result;
        for (int i = 0; i < N; ++i) {
            result.data[i] = data[i] - rhs.data[i];
        }
        return result;
    }
    T operator*(const pixel& rhs) const {
        pixel result;
        for (int i = 0; i < N; ++i) {
            result.data[i] = data[i] * rhs.data[i];
        }
        return result;
    }
    T operator/(const pixel& rhs) const {
        pixel result;
        for (int i = 0; i < N; ++i) {
            result.data[i] = data[i] / rhs.data[i];
        }
        return result;
    }
    T& operator+=(const pixel& rhs) {
        for (int i = 0; i < N; ++i) {
            data[i] += rhs.data[i];
        }
        return *this;
    }
    T& operator-=(const pixel& rhs) {
        for (int i = 0; i < N; ++i) {
            data[i] -= rhs.data[i];
        }
        return *this;
    }
    T& operator*=(const pixel& rhs) {
        for (int i = 0; i < N; ++i) {
            data[i] *= rhs.data[i];
        }
        return *this;
    }
    T& operator/=(const pixel& rhs) {
        for (int i = 0; i < N; ++i) {
            data[i] /= rhs.data[i];
        }
        return *this;
    }

    template<typename U, int N2>
    auto operator=(const pixel<U, N2>& rhs) {
        constexpr int Num = std::min(N, N2);
        memset(data, 0, sizeof(data));
        for (int i = 0; i < Num; ++i) {
            data[i] = color_convert<U, T>(rhs.data[i]);
        }
        return *this;
    }

    template<typename U, int N2>
    operator pixel() {
        pixel<U, N2> result = *this;
        return result;
    }
};

// 图像访问器
template<typename P>
struct image_accessor {
    using pixel_type = typename P::pixel_type;

    image_accessor(void* in_data, const int in_width, const int in_height)
            : data(in_data), width(in_width), height(in_height), row_pitch(in_width * sizeof(P)) {}

    template<typename T>
    image_accessor(void* in_data, const Eigen::Vector2<T>& in_size)
        : data(in_data), width(in_size.x()), height(in_size.y()), row_pitch(in_size.x() * sizeof(P)) {
    }

    /**
     * 将另一个图片复制到此图片
     * @tparam T 源像素格式
     * @param rhs 源图像
     */
    template<typename T>
    void copy_from(const image_accessor<T>& rhs) {
        const int temp_width = std::min(width, rhs.width);
        const int temp_height = std::min(height, rhs.height);
        if constexpr (std::is_same<T, float>::value) {
            auto row_size = std::min(temp_width * sizeof(T), row_pitch);
            for (int y = 0; y < temp_height; ++y) {
                auto src_row = rhs.get_row(y);
                auto dst_row = get_row(y);
                memcpy(dst_row, data, row_size);
            }
        }
        else {
            for (int y = 0; y < temp_height; ++y) {
                for (int x = 0; x < temp_width; ++x) {
                    get_pixel(x, y) = rhs.get_pixel(x, y);
                }
            }
        }
    }

    /**
     * 将另一个图片复制到此图片, 从源图像的指定位置开始
     * @tparam T 源像素格式
     * @param rhs 源图像
     * @param rhs_pos 从源图像的此处开始复制
     */
    template<typename T>
    void copy_from(const image_accessor<T>& rhs, const Eigen::Vector2i& rhs_pos) {
        const int temp_width = std::min(width, rhs.width - rhs_pos.x());
        const int temp_height = std::min(height, rhs.height - rhs_pos.y());
        for (int y = 0; y < temp_height; ++y) {
            for (int x = 0; x < temp_width; ++x) {
                get_pixel(x, y) = rhs.get_pixel(x + rhs_pos.x(), y + rhs_pos.y());
            }
        }
    }

    /**
     * 将另一个图片复制到此图片, 从此图片偏移开始
     * @tparam T 源像素格式
     * @param rhs 源图像
     * @param in_start 从此处开始复制
     */
    template<typename T>
    void offset_copy_from(const image_accessor<T>& rhs, const Eigen::Vector2i& in_start) {
        const int temp_width = std::min(width - in_start.x(), rhs.width);
        const int temp_height = std::min(height - in_start.y(), rhs.height);
        if constexpr (std::is_same<P, T>::value) {
            for (int y = 0; y < temp_height; ++y) {
                auto src_row = rhs.get_row(y);
                auto dst_row = get_row(y + in_start.y()) + in_start.x() * sizeof(T);
                memcpy(dst_row, src_row, temp_width * sizeof(T));
            }
        }
        else {
            for (int y = 0; y < temp_height; ++y) {
                for (int x = 0; x < temp_width; ++x) {
                    get_pixel(x + in_start.x(), y + in_start.y()) = rhs.get_pixel(x, y);
                }
            }
        }
    }

    P& get_pixel(const int x, const int y) {
        if (x < 0 || x >= width || y < 0 || y >= height) {
            throw std::out_of_range("Pixel access out of bounds.");
        }
        const int pixel_size = sizeof(P);
        const int offset = y * row_pitch + x * pixel_size;
        auto data_ptr = static_cast<uint8_t*>(data) + offset;

        return *reinterpret_cast<P*>(data_ptr);
    }
    const P& get_pixel(const int x, const int y) const {
        return const_cast<image_accessor*>(this)->get_pixel(x, y);
    }

    P& operator()(const int x, const int y) {
        return get_pixel(x, y);
    }
    const P& operator()(const int x, const int y) const {
        return get_pixel(x, y);
    }
    P& operator()(const Eigen::Vector2i& pos) {
        return get_pixel(pos.x(), pos.y());
    }
    P& operator()(const Eigen::Vector2i& pos) const {
        return get_pixel(pos.x(), pos.y());
    }

    void set_row_pitch(const int in_row_pitch) {
        assert(in_row_pitch >= width);
        row_pitch = in_row_pitch;
    }
    void flip_y() {
        std::vector<uint8_t> temp_row(row_pitch);  // 临时存储一行数据

        for (size_t y = 0; y < height / 2; ++y) {
            // 计算要交换的两行的起始地址
            uint8_t* top_row = (uint8_t*)data + y * row_pitch;
            uint8_t* bottom_row = (uint8_t*)data + (height - 1 - y) * row_pitch;

            // 交换两行数据
            std::memcpy(temp_row.data(), top_row, row_pitch);    // 将 top_row 保存到临时缓冲区
            std::memcpy(top_row, bottom_row, row_pitch);         // 将 bottom_row 移动到 top_row
            std::memcpy(bottom_row, temp_row.data(), row_pitch); // 将临时缓冲区的数据移动到 bottom_row
        }
    }

    void* const data;
    const int width;
    const int height;
    int row_pitch; // 行跨度，支持对齐
private:
    uint8_t* get_row(const int y) const {
        return (uint8_t*)data + y * row_pitch;
    }
};

using pixel_r8 = pixel<uint8_t, 1>;
using pixel_rg8 = pixel<uint8_t, 2>;
using pixel_rgb8 = pixel<uint8_t, 3>;
using pixel_rgba8 = pixel<uint8_t, 4>;
using pixel_a8 = pixel<uint8_t, 1>;

using pixel_r16 = pixel<uint16_t, 1>;
using pixel_rg16 = pixel<uint16_t, 2>;
using pixel_rgb16 = pixel<uint16_t, 3>;
using pixel_rgba16 = pixel<uint16_t, 4>;
using pixel_a16 = pixel<uint16_t, 1>;

using pixel_r16f = pixel<Eigen::half, 1>;
using pixel_rg16f = pixel<Eigen::half, 2>;
using pixel_rgb16f = pixel<Eigen::half, 3>;
using pixel_rgba16f = pixel<Eigen::half, 4>;
using pixel_a16f = pixel<Eigen::half, 1>;

using pixel_r = pixel<float, 1>;
using pixel_rg = pixel<float, 2>;
using pixel_rgb = pixel<float, 3>;
using pixel_rgba = pixel<float, 4>;
using pixel_a = pixel<float, 1>;
