#ifndef PREPROCESS_KERNEL_CUH
#define PREPROCESS_KERNEL_CUH

#include "preprocess_kernel/hip_tools.hpp"
#include <hip/hip_runtime_api.h>

namespace AIKernel{

    enum class NormType : int{
        None      = 0,
        MeanStd   = 1,
        AlphaBeta = 2
    };

    enum class ChannelType : int{
        None          = 0,
        Invert        = 1
    };

    struct Norm{
        float mean[3];
        float std[3];
        float alpha, beta;
        NormType type = NormType::None;
        ChannelType channel_type = ChannelType::None;

        // out = (x * alpha - mean) / std
        static Norm mean_std(const float mean[3], const float std[3], float alpha = 1/255.0f, ChannelType channel_type=ChannelType::None);

        // out = x * alpha + beta
        static Norm alpha_beta(float alpha, float beta = 0, ChannelType channel_type=ChannelType::None);

        // None
        static Norm None();
    };

    /************************************************************************
    函　数　名：GetImgAvgBright
    功　　　能：进行GPU上的图像亮度计算
    参　　　数：src         [IN] 图像地址; 
               width:      [IN] 图像宽度; 
               height:     [IN] 图像高度;
               linesize:   [IN] 图像一行的字节数; 
               &avgBright:  [OUT] 平均亮度 ; 
    返　回  值：无
    ************************************************************************/
    void GetImgAvgBright(
        const uint8_t* src, int width, int height, int linesize, float& avgBright
    );

    //
    // 使用示范:
    // 
    // float* pfMatrix_dev = nullptr;
    // size_t matrix_bytes = 3 * 3 * sizeof(f32);
    // checkCudaRuntime(cudaMalloc(&pfMatrix_dev, matrix_bytes));
    // checkCudaRuntime(cudaMemset(pfMatrix_dev, 0,  matrix_bytes));
    //
    // #左上、右上、右下、左下 原图像四个点的坐标
    //    cv::Point2f src_points[] = { 
    //    vctvctPoints[nImageIdx][0],
    //    vctvctPoints[nImageIdx][1],
    //    vctvctPoints[nImageIdx][2],
    //    vctvctPoints[nImageIdx][3]};
    // 
    // #左上、右上、左下、右下（Z 字形排列） 目标图像四个点的坐标
    //    cv::Point2f dst_points[] = {
    //        cv::Point2f(0, 0),
    //        cv::Point2f(nw, 0),
    //        cv::Point2f(0, nh),
    //        cv::Point2f(nw, nh) };
    // 利用opencv 得到变换矩阵
    //    cv::Mat tfMatrix_org = cv::getPerspectiveTransform(src_points, dst_points);
    //    cv::Mat tfMatrix_I;
    // 得到变换矩阵的逆矩阵
    //    cv::invert(tfMatrix_org, tfMatrix_I);
    //    tfMatrix_I.convertTo(tfMatrix_I,  CV_32FC1);
    // 拷贝到 gpu 
    //    checkCudaRuntime(cudaMemcpy(pfMatrix_dev, tfMatrix_I.data, matrix_bytes, cudaMemcpyHostToDevice));

    void Perspective_gpu(
        uint8_t* src, int src_line_size, int src_width, int src_height, float* dst, int dst_width, int dst_height,
		float* matrix_3_3, uint8_t const_value, const Norm& norm
        );

    void obtain_roi(
    uint8_t* src, int src_line_step, int src_width, int src_height, uint8_t* dst, int x, int y, int dst_width, int dst_height,
    hipStream_t stream);
    
    void resize_bilinear_and_normalize(
		uint8_t* src, int src_line_size, int src_width, int src_height, float* dst, int dst_width, int dst_height,
		const Norm& norm);

    void resize_bilinear_and_normalize_two_steps(
		uint8_t* src, float* resize_buffer, int src_line_size, int src_width, int src_height, float* dst, int dst_width, int dst_height,
		const Norm& norm,
		hipStream_t stream);

    void warp_affine_bilinear_and_normalize_plane(
        uint8_t* src, int src_line_size, int src_width, int src_height, 
        float* dst  , int dst_width, int dst_height,
        float* matrix_2_3, uint8_t const_value, const Norm& norm,
        hipStream_t stream);

    void warp_affine(
        uint8_t* src, int src_line_size, int src_width, int src_height, 
        uint8_t* dst  , int dst_width, int dst_height,
        float* matrix_2_3, uint8_t const_value, hipStream_t& stream);
    
    void warp_affine_bilinear_and_normalize_focus(
        uint8_t* src, int src_line_size, int src_width, int src_height, 
        float* dst  , int dst_width, int dst_height,
        float* matrix_2_3, uint8_t const_value, const Norm& norm,
        hipStream_t stream);

    void norm_feature(
        float* feature_array, int num_feature, int feature_length,
        hipStream_t stream
    );

    void convert_nv12_to_bgr_invoke(
        const uint8_t* y, const uint8_t* uv, int width, int height, 
        int linesize, uint8_t* dst, 
        hipStream_t stream);
};

#endif // PREPROCESS_KERNEL_CUH