/**
 * @file visual_sender.c
 * @brief 视觉图片分帧发送协议实现
 */

#include "protocol/visual_sender.h"
#include "engine_internal.h"
#include "base64_codec.h"
#include "connection/connection_manager.h"
#include "hal_log.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define TAG "VISUAL"

#define IMG_PREFIX        "[E]:[IMG]:"
#define IMG_PREFIX_LEN    10
#define IMG_FRAME_RAW_MAX 1089
#define IMG_FRAME_TXT_MAX (((IMG_FRAME_RAW_MAX + 64) + 2) / 3 * 4)
#define IMG_HDR_FIRST     0x18u  /* HeaderV=1, Start=1 */
#define IMG_HDR_CONT      0x10u  /* HeaderV=1, 中间帧 */
#define IMG_END_FRAME     "[E]:[IMG]:FA=="

/**
 * @brief 校验图片 magic bytes
 * @return 1=JPEG, 2=PNG, 0=unknown
 */
static int check_image_magic(const uint8_t *data, size_t len)
{
    if (len < 4) {
        return 0;
    }
    if (data[0] == 0xFFu && data[1] == 0xD8u) {
        return 1;
    }
    if (data[0] == 0x89u && data[1] == 0x50u
        && data[2] == 0x4Eu && data[3] == 0x47u) {
        return 2;
    }
    return 0;
}

int visual_send_image(engine_internal_ctx_t *ctx,
                      const uint8_t *data, size_t len)
{
    if (!ctx || !data || len == 0) {
        return -1;
    }
    if (!conn_mgr_is_connected(ctx)) {
        return -1;
    }

    int img_type = check_image_magic(data, len);
    if (img_type == 0) {
        BD_LOGW(TAG, "not JPEG/PNG (magic %02x %02x)",
                data[0], data[1]);
        return -1;
    }

    /* 元数据 */
    char meta[64];
    int meta_len = snprintf(meta, sizeof(meta),
                            "[T]=binary;[N]=photo.jpg;\n");
    if (meta_len <= 0 || meta_len >= (int)sizeof(meta)) {
        return -1;
    }

    uint8_t *raw_buf = (uint8_t *)malloc(IMG_FRAME_RAW_MAX);
    char *txt_buf = (char *)malloc(
        IMG_PREFIX_LEN + IMG_FRAME_TXT_MAX + 4);
    if (!raw_buf || !txt_buf) {
        free(raw_buf);
        free(txt_buf);
        BD_LOGW(TAG, "malloc failed");
        return -1;
    }
    memcpy(txt_buf, IMG_PREFIX, IMG_PREFIX_LEN);

    BD_LOGI(TAG, "send image: %u bytes (%s)",
            (unsigned)len, (img_type == 1) ? "JPEG" : "PNG");

    int ret = 0;
    int chunk_count = 0;
    int is_first = 1;
    size_t offset = 0;

    while (offset < len) {
        unsigned int hdr_len = 0u;
        if (is_first) {
            raw_buf[0] = (uint8_t)IMG_HDR_FIRST;
            memcpy(raw_buf + 1, meta, (size_t)meta_len);
            hdr_len = 1u + (unsigned int)meta_len;
        } else {
            raw_buf[0] = (uint8_t)IMG_HDR_CONT;
            hdr_len = 1u;
        }

        unsigned int max_data =
            (unsigned int)IMG_FRAME_RAW_MAX - hdr_len;
        unsigned int data_chunk = (unsigned int)(len - offset);
        if (data_chunk > max_data) {
            data_chunk = max_data;
        }
        memcpy(raw_buf + hdr_len, data + offset, data_chunk);

        unsigned int raw_total = hdr_len + data_chunk;
        int b64_len = base64_codec_encode(
            raw_buf, raw_total,
            txt_buf + IMG_PREFIX_LEN, IMG_FRAME_TXT_MAX + 1);
        if (b64_len <= 0) {
            BD_LOGW(TAG, "base64 encode failed (chunk %d)",
                    chunk_count);
            ret = -1;
            break;
        }
        txt_buf[IMG_PREFIX_LEN + b64_len] = '\0';

        ret = conn_mgr_send_text(ctx, txt_buf);
        if (ret < 0) {
            BD_LOGW(TAG, "chunk %d send failed", chunk_count);
            break;
        }

        offset += data_chunk;
        chunk_count++;
        is_first = 0;
    }

    /* 末帧 */
    if (ret >= 0) {
        ret = conn_mgr_send_text(ctx, IMG_END_FRAME);
        if (ret < 0) {
            BD_LOGW(TAG, "end frame send failed");
        }
    }

    free(raw_buf);
    free(txt_buf);

    if (ret >= 0) {
        BD_LOGI(TAG, "send image done: %d chunks", chunk_count);
    }
    return ret;
}