#ifndef VMF_VIDEO_SOURCE_H
#define VMF_VIDEO_SOURCE_H

#include <stdint.h>

typedef struct VMF_VSRC_HANDLE_S VMF_VSRC_HANDLE_T;
typedef void (*VMF_VSRC_CALLBACK_T)(void *arg, void *buf_info);

/* Gyro daemon config — matches real SDK gyro_daemon.h (VMF_VSRC_GYRO_CONFIG_T) */
typedef struct {
    unsigned long ulDeviceNum;   /* device number (default: 1) */
    unsigned int  dwSpeed;       /* polling speed in fps (default: 30) */
    unsigned int  dwFrequency;   /* iio sample frequency (default: 200) */
    int           sdwGyroFsr;    /* gyro full-scale range; -1 = unchanged */
    int           sdwAccelFsr;   /* accel full-scale range; -1 = unchanged */
    unsigned int  dwSampleCount; /* gyro buffer depth (default: 200) */
    char         *pszPinName;    /* SCM output pin name */
} VMF_VSRC_GYRO_CONFIG_T;

/* EIS init config — all fields accessed by set_eis() in kdp2_host_stream.c */
typedef struct {
    char                *pszLensCurveNodesPath;
    char                *pszLogPath;
    float                fGyroDataGain;
    uint32_t             dwGridSection;
    uint32_t             dwMaxGridSection;
    float                fCropRatio;
    uint32_t             dwImageType;
    uint32_t             dwProcessMode;
    uint32_t             dwCoordinateTransform[3];
    int64_t              sqwTimeOffset;
    uint32_t             bImageRotate180;
    int32_t              sdwReadoutTimeOffset;
    float                fReadoutTimeRatio;
    uint32_t             bForceOriRs;
    VMF_VSRC_GYRO_CONFIG_T tGyroConfig;
    uint32_t             _pad[8];
} VMF_EIS_INIT_T;

/* FEC init config — the REAL VMF_VSRC_FEC_INIT_CONFIG_T layout, deduced from fec_api.c
 * field access patterns. VMF_VSRC_Init reads up to afLensCurveNodeY[63], so the
 * struct must cover at least 536 bytes to prevent stack overread → SIGSEGV.
 *
 * Confirmed field order from loadCalibrateConfig / loadFECConfig in fec_api.c:
 *   offset  0: eFecMethod   (uint32_t) — VMF_FEC_METHOD
 *   offset  4: ptEisInit    (ptr)      — EIS init (NULL if EIS disabled)
 *   offset  8: iFecCenterOffsetX (int32_t)
 *   offset 12: iFecCenterOffsetY (int32_t)
 *   offset 16: iFecRadiusOffset  (int32_t)
 *   offset 20: dwLensCurveNodeNum (uint32_t) — 0 = no lens correction
 *   offset 24: afLensCurveNodeX[64] (float[64], 256 bytes)
 *   offset 280: afLensCurveNodeY[64] (float[64], 256 bytes)
 *   offset 536: _pad[64] extra safety
 */
typedef struct {
    uint32_t        eFecMethod;            /* offset   0 */
    VMF_EIS_INIT_T *ptEisInit;             /* offset   4 */
    int32_t         iFecCenterOffsetX;     /* offset   8 */
    int32_t         iFecCenterOffsetY;     /* offset  12 */
    int32_t         iFecRadiusOffset;      /* offset  16 */
    uint32_t        dwLensCurveNodeNum;    /* offset  20 — 0 = no correction */
    float           afLensCurveNodeX[64]; /* offset  24  (256 bytes) */
    float           afLensCurveNodeY[64]; /* offset 280  (256 bytes) */
    uint32_t        _pad[64];             /* offset 536  (256 bytes extra safety) */
} VMF_FEC_INIT_CONFIG_T;                  /* total: 792 bytes */

/* Alias used by the real fec_api.c */
typedef VMF_FEC_INIT_CONFIG_T VMF_VSRC_FEC_INIT_CONFIG_T;

/* Frontend config — confirmed real layout from VSRC_Front_Init_Normal disasm (0x3ec08):
 *   r8 = initopt[8] = ptFrontConfig
 *   [r8, #0]  = dwSensorConfigCount  ← checked: if 0 → "sensor config should not be empty"
 *   [r8, #4]  = apszSensorConfig[0]  ← loaded for sensor 0
 *   [r8, #8]  = apszSensorConfig[1]  ← loaded for sensor 1 (fusion)
 *   [r8, #12] = apszSensorConfig[2]
 *   [r8, #16] = apszSensorConfig[3]
 *   [r8, #20] = tFecInitConfig (eFecMethod, ptEisInit, ...) */
typedef struct {
    uint32_t              dwSensorConfigCount; /* offset  0 — MUST BE FIRST */
    const char           *apszSensorConfig[4]; /* offset  4 (16 bytes) */
    VMF_FEC_INIT_CONFIG_T tFecInitConfig;      /* offset 20 (792 bytes) */
    uint32_t              _pad[8];             /* offset 812, extra safety */
} VMF_VSRC_FRONTEND_CONFIG_T;

/*
 * VMF_LAYOUT_T — layout descriptor used for FEC and video positioning.
 */
typedef struct {
    uint32_t dwCanvasWidth;
    uint32_t dwCanvasHeight;
    uint32_t dwVideoPosX;
    uint32_t dwVideoPosY;
    uint32_t dwVideoWidth;
    uint32_t dwVideoHeight;
    uint32_t _pad[58];
} VMF_LAYOUT_T;

/* ISP option flag */
#define ISP_OPTION_PRIVACY_MASK_SETTINGS  1u

typedef struct {
    uint32_t option_flag;
    uint32_t adwData[4];
    uint32_t _pad[8];
} VMF_ISP_OPTION_T;

typedef struct {
    uint32_t       bEnable;
    uint8_t        abyColorYUV[3];
    uint8_t        _reserved1;
    uint32_t       dwMaskStride;
    uint32_t       bMainMaskDisable;
    uint32_t       bResizeMaskDisable;
    unsigned char *pMaskBuffer;
    uint32_t       _pad[4];
} VMF_ISP_PM_CONFIG_T;

/* ISP mode enum */
typedef enum {
    VMF_ISP_MODE_NORMAL  = 0,
    VMF_ISP_MODE_FEC     = 1,
    VMF_ISP_MODE_FEC_C   = 2,
    VMF_ISP_MODE_EIS     = 3,
} VMF_ISP_MODE_E;

/* Encoder spec bits (nested in VMF_VSRC_SPEC_CONFIG_T.tIspEncSpec) */
typedef struct {
    uint32_t bEncH265;
    uint32_t bEncH264;
    uint32_t bEncJPEG;
    uint32_t bOthers;
} VMF_ISP_ENC_SPEC_T;

/* Spec config — fields accessed by setup_spec() in kdp2_host_stream.c.
 * Real size = 24 bytes (no padding): bEnableSpec(4)+dwIspMode(4)+tIspEncSpec(16).
 * Confirmed: fp[36]=bEnableSpec→handle[992], fp[40-47]=vld1.32(dwIspMode+tIspEncSpec[0])→handle[1012]. */
typedef struct {
    uint32_t           bEnableSpec;
    uint32_t           dwIspMode;    /* VMF_ISP_MODE_E */
    VMF_ISP_ENC_SPEC_T tIspEncSpec;
    /* NO padding — struct is 24 bytes; placed at initopt[36] per disasm */
} VMF_VSRC_SPEC_CONFIG_T;

/* App mode enum */
typedef enum {
    VMF_VSRC_APP_MODE_NORMAL = 0,
    VMF_VSRC_APP_MODE_FUSION = 1,
} VMF_VSRC_APP_MODE_E;

/* Init callback type */
typedef void (*VMF_VSRC_INIT_CALLBACK_T)(uint32_t width, uint32_t height);

/*
 * VMF_VSRC_INITOPT_T — confirmed offsets from libvmf.so disassembly:
 *
 *  [r4,#0]   = eAppMode        — jump table 0-8 in sub_30a80; NORMAL=0, FUSION=1
 *  [r4,#4]   = dwFrontConfigCount — CHECKED: must be 1-2 (VMF_VSRC_Init@32080)
 *  [r4,#8]   = ptFrontConfig   — CHECKED: must be non-NULL (VMF_VSRC_Init@3208c)
 *  [r4,#12]  = fnInitCallback  — init-done callback (placed after ptFrontConfig)
 *  [r4,#16]  = _unk[5]         — unknown fields (20 bytes)
 *  [r4,#36]  = tSpecConfig     — bEnableSpec→handle[992], vld1.32[40-47]→handle[1012]
 *  [r4,#60]  = _unk2[5]        — unknown (20 bytes, before pszAutoSceneConfig)
 *  [r4,#80]  = pszAutoSceneConfig — nullable string, conditional strdup→handle[204]
 *  [r4,#84]  = _unk3[11]       — unknown (44 bytes)
 *  [r4,#128] = bShared         — CHECKED boolean→handle[212] (VMF_VSRC_Init sub_30a80@30ac4)
 *  [r4,#132] = pszOutPinPrefix — CHECKED non-NULL; strncpy(9)→handle[188] (@30ae8)
 *  [r4,#136] = _unk6           — unknown (4 bytes)
 *  [r4,#140] = pszResourceDir  — strdup→handle[200] (@30afc)
 *  [r4,#144] = _unk7[10]       — unknown tail fields
 */
typedef struct {
    VMF_VSRC_APP_MODE_E        eAppMode;           /* offset   0 */
    uint32_t                   dwFrontConfigCount; /* offset   4 */
    VMF_VSRC_FRONTEND_CONFIG_T *ptFrontConfig;     /* offset   8 */
    VMF_VSRC_INIT_CALLBACK_T   fnInitCallback;     /* offset  12 */
    uint32_t                   _unk[5];            /* offset  16 (20 bytes) */
    VMF_VSRC_SPEC_CONFIG_T     tSpecConfig;        /* offset  36 (24 bytes) */
    uint32_t                   _unk2[5];           /* offset  60 (20 bytes) */
    const char                *pszAutoSceneConfig; /* offset  80 */
    uint32_t                   _unk3[11];          /* offset  84 (44 bytes) */
    uint32_t                   bShared;            /* offset 128 */
    const char                *pszOutPinPrefix;    /* offset 132 */
    uint32_t                   _unk6;              /* offset 136 */
    const char                *pszResourceDir;     /* offset 140 */
    uint32_t                   _unk7[10];          /* offset 144 (40 bytes) */
} VMF_VSRC_INITOPT_T;

VMF_VSRC_HANDLE_T *VMF_VSRC_Init(VMF_VSRC_INITOPT_T *initopt);
void               VMF_VSRC_Release(VMF_VSRC_HANDLE_T *hVsrc);
int VMF_VSRC_Open(VMF_VSRC_HANDLE_T **handle, const char *cfg_path);
int VMF_VSRC_Close(VMF_VSRC_HANDLE_T *handle);
int VMF_VSRC_Start(VMF_VSRC_HANDLE_T *handle, void *arg);
int VMF_VSRC_Stop(VMF_VSRC_HANDLE_T *handle);
int VMF_VSRC_Suspend(VMF_VSRC_HANDLE_T *handle);
int VMF_VSRC_Resume(VMF_VSRC_HANDLE_T *handle);
int VMF_VSRC_SetFrontendConfig(VMF_VSRC_HANDLE_T *handle, VMF_VSRC_FRONTEND_CONFIG_T *cfg);
int VMF_VSRC_ConfigISP(VMF_VSRC_HANDLE_T *h, int stream, int layer, int isp, VMF_ISP_OPTION_T *opt);
void *VMF_VSRC_GetInfo(VMF_VSRC_HANDLE_T *h, uint32_t idx, void *info);

/* Pull in FEC method enum (VMF_FEC_METHOD_GTR etc.) — safe due to include guards */
#include <vmf/fec_layout.h>

#endif /* VMF_VIDEO_SOURCE_H */
