/*
 * CDQ Dump - Export coefficient data in CDQ format
 * For VPU hardware verification
 *
 * 36-bit format with flags at [3:0]:
 *   SOU:  [35:34]=rsvd [33:32]=bit_depth [31:24]=sb_row [23:16]=sb_col [15:12]=mode [11:8]=sb_size [7:4]=rsvd [3:0]=flags
 *   SOT:  [35:34]=plane_id [33:26]=dc_qidx [25:18]=ac_qidx [17:13]=tx_type [12:8]=tx_size [7:4]=rsvd [3:0]=flags
 *   COEF: [35:24]=scan_pos(12) [23:4]=coef(20 signed) [3:0]=flags
 */

#ifndef CDQ_DUMP_H_
#define CDQ_DUMP_H_

#include <stdint.h>
#include <stdio.h>

// CDQ flags (bits [3:0]) - combinable
#define CDQ_FLAG_SOU  0x1   // Start of Unit (SuperBlock)
#define CDQ_FLAG_SOT  0x2   // Start of Transform
#define CDQ_FLAG_EOT  0x4   // End of Transform
#define CDQ_FLAG_EOU  0x8   // End of Unit (SuperBlock)

// Mode values (bits [15:12] of SOU)
#define CDQ_MODE_AV1  0x1
#define CDQ_MODE_AV2  0x2
#define CDQ_MODE_VP9  0x9

// SB size values (bits [11:8] of SOU)
#define CDQ_SB_64    0x0
#define CDQ_SB_128   0x1
#define CDQ_SB_256   0x2

// Bit depth values (bits [33:32] of SOU)
#define CDQ_BD_8   0x0
#define CDQ_BD_10  0x1
#define CDQ_BD_12  0x2

// Plane ID values (bits [35:34] of SOT)
#define CDQ_PLANE_Y  0x0
#define CDQ_PLANE_U  0x1
#define CDQ_PLANE_V  0x2

// Pending element types for deferred write
#define CDQ_PENDING_NONE  0
#define CDQ_PENDING_SOT   1
#define CDQ_PENDING_COEF  2

// CDQ dump context
typedef struct CdqDumpCtx {
    FILE *fp;
    char *output_dir;
    int frame_num;
    int tile_row;       // current tile row
    int tile_col;       // current tile column
    int sb_count;       // superblocks in current tile
    int block_count;    // transform blocks total
    int coef_count;     // coefficients total
    int enabled;
    int sb_size;        // 0=64, 1=128, 2=256
    int mode;           // 1=AV1, 2=AV2, 9=VP9
    int bit_depth;      // 0=8bit, 1=10bit, 2=12bit
    // Pending SOU - deferred until we know if SB has data
    int pending_sou;        // 1 if SOU waiting to be emitted
    int pending_sou_row;
    int pending_sou_col;
    // Deferred write - last element waiting to be written
    int pending_type;       // 0=none, 1=SOT, 2=COEF
    int pending_flags;      // flags for pending element
    uint64_t pending_data;  // 36-bit word
    // Extra fields for JSON output
    int pending_plane_id;
    int pending_dc_qidx;
    int pending_ac_qidx;
    int pending_tx_type;
    int pending_tx_size;
    int pending_scan_pos;
    int32_t pending_coef;   // 20-bit signed coefficient
} CdqDumpCtx;

// Get global CDQ context
CdqDumpCtx *cdq_get_global_ctx(void);

// Initialize CDQ dump
void cdq_dump_init(CdqDumpCtx *ctx, const char *output_dir);

// Close CDQ dump
void cdq_dump_close(CdqDumpCtx *ctx);

// Start new frame (resets counters)
void cdq_dump_start_frame(CdqDumpCtx *ctx, int frame_num, int mode, int sb_size, int bit_depth);

// End frame
void cdq_dump_end_frame(CdqDumpCtx *ctx);

// Start new tile (opens per-tile file)
void cdq_dump_start_tile(CdqDumpCtx *ctx, int tile_row, int tile_col);

// End tile (closes per-tile file)
void cdq_dump_end_tile(CdqDumpCtx *ctx);

// Start new SuperBlock - deferred until first data or next SB
void cdq_dump_start_sb(CdqDumpCtx *ctx, int sb_row, int sb_col);

// Emit SOT word (start of transform block)
// plane_id: 0=Y, 1=U, 2=V
void cdq_dump_sot(CdqDumpCtx *ctx, int plane_id, int dc_qidx, int ac_qidx,
                  int tx_type, int tx_size, int is_skip);

// Emit coefficient (20-bit signed)
void cdq_dump_coef(CdqDumpCtx *ctx, int scan_pos, int32_t coef, int is_eot);

// Build 36-bit SOU word
// [35:34]=rsvd [33:32]=bit_depth [31:24]=sb_row [23:16]=sb_col [15:12]=mode [11:8]=sb_size [7:4]=rsvd [3:0]=flags
static inline uint64_t cdq_build_sou(int flags, int bit_depth, int sb_row, int sb_col, int mode, int sb_size) {
    return ((uint64_t)(bit_depth & 0x3) << 32) |
           ((uint64_t)(sb_row & 0xFF) << 24) |
           ((uint64_t)(sb_col & 0xFF) << 16) |
           ((uint64_t)(mode & 0xF) << 12) |
           ((uint64_t)(sb_size & 0xF) << 8) |
           (flags & 0xF);
}

// Build 36-bit SOT word
// [35:34]=plane_id [33:26]=dc_qidx [25:18]=ac_qidx [17:13]=tx_type [12:8]=tx_size [7:4]=rsvd [3:0]=flags
static inline uint64_t cdq_build_sot(int flags, int plane_id, int dc_qidx, int ac_qidx, int tx_type, int tx_size) {
    return ((uint64_t)(plane_id & 0x3) << 34) |
           ((uint64_t)(dc_qidx & 0xFF) << 26) |
           ((uint64_t)(ac_qidx & 0xFF) << 18) |
           ((uint64_t)(tx_type & 0x1F) << 13) |
           ((uint64_t)(tx_size & 0x1F) << 8) |
           (flags & 0xF);
}

// Build 36-bit COEF word
// [35:24]=scan_pos(12) [23:4]=coef(20 signed) [3:0]=flags
static inline uint64_t cdq_build_coef(int flags, int scan_pos, int32_t coef) {
    // Sign-extend coef to 20 bits
    uint32_t coef_20 = (uint32_t)(coef & 0xFFFFF);
    return ((uint64_t)(scan_pos & 0xFFF) << 24) |
           ((uint64_t)coef_20 << 4) |
           (flags & 0xF);
}

#endif  // CDQ_DUMP_H_
