/*
 * SPDX-License-Identifier: Apache 2.0 License
 *
 * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
 */

#pragma once

#include "esp_err.h"
#include <esp_idf_version.h>

#ifdef __cplusplus
extern "C" {
#endif

#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))
#define DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#else
#define DEPRECATED_ATTRIBUTE
#endif

typedef void *esp_delta_ota_handle_t;

// Callback for reading the source data
typedef esp_err_t (*src_read_cb_t)(uint8_t *buf_p, size_t size, int src_offset);
typedef esp_err_t (*src_read_cb_with_user_ctx_t)(uint8_t *buf_p, size_t size, int src_offset, void *user_data);

// Callback for working on the data generated by applying patch on the source data
typedef esp_err_t (*merged_stream_write_cb_t)(const uint8_t *buf_p, size_t size);
typedef esp_err_t (*merged_stream_write_cb_with_user_ctx_t)(const uint8_t *buf_p, size_t size, void *user_data);

typedef struct esp_delta_ota_cfg {
    void *user_data;              /*!< User Data */
    union {
        src_read_cb_t read_cb;        /*!< Read Callback */
        src_read_cb_with_user_ctx_t read_cb_with_user_data; /*!< Read Callback with user data */
    };
    union {
        merged_stream_write_cb_with_user_ctx_t write_cb_with_user_data;     /*!< Write Callback with user data */
        merged_stream_write_cb_t write_cb DEPRECATED_ATTRIBUTE;             /*!< Write Callback */
    };
} esp_delta_ota_cfg_t;

#undef DEPRECATED_ATTRIBUTE

/**
 * @brief Initializes the delta OTA process
 *
 * @param[in] cfg pointer to esp_delta_ota_cfg_t structure.
 * @return - NULL   On failure
 *         - esp_delta_ota_handle_t handle
 */
esp_delta_ota_handle_t esp_delta_ota_init(esp_delta_ota_cfg_t *cfg);

/**
 * @brief This function performs the patch applying operation on the source data.
 *
 * @param[in] handle    esp_delta_ota_handle_t handle
 * @param[in] buf       pointer to patch buffer
 * @param[in] size      size of patch buffer.
 * @return - ESP_OK
 *         - ESP_ERR_INVALID_ARG
 *         - ESP_FAIL
 */
esp_err_t esp_delta_ota_feed_patch(esp_delta_ota_handle_t handle, const uint8_t *buf, int size);

/**
 * @brief This function finishes the patch applying operation.
 *
 * @param[in] handle    esp_delta_ota_handle_t
 * @return int
 */
esp_err_t esp_delta_ota_finalize(esp_delta_ota_handle_t handle);

/**
 * @brief Clean-up delta ota process
 *
 * @param[in] handle    esp_delta_ota_handle_t
 */
esp_err_t esp_delta_ota_deinit(esp_delta_ota_handle_t handle);

#ifdef __cplusplus
}
#endif
