#pragma once

#include <tuple>
#include <utility>

#include "k_video_comm.h"
#include "mpi_vicap_api.h"

enum class SensorPixelFormat {
    InvaildPixelFormat = -1,
    GRAYSCALE          = 0,
    RGB565,
    RGB888,
    RGB888P, // RGB888 Planar
    YUV420SP,
};

class Sensor {
public:
    Sensor(int csiNum, int reqWidth = 1920, int reqHeight = 1080, int reqFps = 60);
    ~Sensor();

    Sensor(const Sensor&)            = delete;
    Sensor& operator=(const Sensor&) = delete;
    Sensor(Sensor&&)                 = delete;
    Sensor& operator=(Sensor&&)      = delete;

    int reset();

    int                  set_framesize(int width, int height, bool crop = false, k_vicap_chn channel = VICAP_CHN_ID_0);
    int                  set_framesize(int width, int height, int crop_x, int crop_y, int crop_width, int crop_height,
                                       k_vicap_chn channel = VICAP_CHN_ID_0);
    std::tuple<int, int> framesize(k_vicap_chn channel = VICAP_CHN_ID_0) const;

    int               set_pixformat(SensorPixelFormat pixelFormat, k_vicap_chn channel = VICAP_CHN_ID_0);
    SensorPixelFormat pixformat(k_vicap_chn channel = VICAP_CHN_ID_0) const;

    int  set_hmirror(bool enable = false);
    bool hmirror();

    int  set_vflip(bool enable = false);
    bool vflip();

    int run(k_vicap_work_mode mode = VICAP_WORK_ONLINE_MODE);
    int stop();

    int snapshot(k_video_frame_info& info, k_vicap_chn channel = VICAP_CHN_ID_0, int timeoutMs = 1000);

    int _set_alignment(int alignment, k_vicap_chn channel = VICAP_CHN_ID_0);
    int _set_fps(int fps, k_vicap_chn channel = VICAP_CHN_ID_0);

    int _dev_id() { return static_cast<int>(m_vicapDev); }

    static k_pixel_format to_k_pixel_format(SensorPixelFormat pixel_format)
    {
        switch (pixel_format) {
        case SensorPixelFormat::InvaildPixelFormat: {
            return PIXEL_FORMAT_BUTT;
        } break;
        case SensorPixelFormat::GRAYSCALE:
        case SensorPixelFormat::YUV420SP: {
            return PIXEL_FORMAT_YUV_SEMIPLANAR_420;
        } break;
        case SensorPixelFormat::RGB565:
        case SensorPixelFormat::RGB888: {
            return PIXEL_FORMAT_RGB_888;
        } break;
        case SensorPixelFormat::RGB888P: {
            return PIXEL_FORMAT_RGB_888_PLANAR;
        } break;
        default: {
            return PIXEL_FORMAT_BUTT;
        } break;
        }

        return PIXEL_FORMAT_BUTT;
    }

private:
    bool can_set_framesize_and_format(k_vicap_chn channel);

    static std::tuple<int, int, int, int> calculate_crop(int inputWidht, int inputHight, int targetWidth, int targetHeight);

    static k_vicap_dev s_vicapDevIndex;

    bool m_reseted;
    bool m_started;

    k_vicap_dev m_vicapDev;

    k_vicap_probe_config m_probeConfig;
    k_vicap_sensor_info  m_sensorInfo;

    k_vicap_dev_attr  m_deviceAttr;
    k_vicap_chn_attr  m_channelAttr[VICAP_CHN_ID_MAX];
    SensorPixelFormat m_pixelFormat[VICAP_CHN_ID_MAX];

    std::pair<bool, k_video_frame_info> m_dumpedVideoFrame[VICAP_CHN_ID_MAX];
};
