#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/ringbuf.h"
#include "esp_err.h"
#include "esp_log.h"
#include "usb/usb_host.h"
#include "msc/include/msc_host.h"
#include "msc/include/msc_host_vfs.h"
#include "ffconf.h"
#include "ff.h"
#include "errno.h"
#include "esp_vfs.h"

#include "spbelib_interface.h"

#include "config/hardware_define.h"
// #include "usb/cdc_acm_host.h"

#include "usbport.h"

#define CONFIG_SYS_LOG_DUMP_ON 0
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
#define SYS_LOG_DOMAIN "USB"
#include "sys_log.h"

#define IN_RINGBUF_SIZE (1024 * 1)
#define OUT_RINGBUF_SIZE (1024 * 1)

#define CDC_CHECK(a, str, ret) \
    do                         \
    {                          \
        if (!(a))              \
        {                      \
            SYS_LOG_ERR(str);  \
            return (ret);      \
        }                      \
    } while (0)

#define CDC_CHECK_GOTO(a, str, lable) \
    do                                \
    {                                 \
        if (!(a))                     \
        {                             \
            SYS_LOG_ERR(str);         \
            goto lable;               \
        }                             \
    } while (0)

typedef struct
{
    os_pipe_t pipe_obj;
    os_work_t *rx_resume_work;
} __usb_data_t;

static QueueHandle_t app_queue;
// static SemaphoreHandle_t ready_to_uninstall_usb;
static msc_host_vfs_handle_t vfs_handle;

static usbport_status_e g_usb_status = USBPORT_STATUS_NO_CONNECTION;
static __usb_data_t s_usb_data;
static sb_data_port_t s_port;
static msc_host_device_handle_t g_connected_usb_device = NULL;
static cdc_acm_dev_hdl_t g_cdc_dev;

//////////// CDC 全局变量 ////////////

#define BULK_OUT_URB_NUM 2
#define BULK_IN_URB_NUM 2
#define BUFFER_SIZE_BULK_OUT 512
#define BUFFER_SIZE_BULK_IN 512
#define USB_TASK_KILL_BIT BIT1
#define CDC_DATA_TASK_KILL_BIT BIT4
#define CDC_DEVICE_READY_BIT BIT19
#define TIMEOUT_USB_RINGBUF_MS 200 // Timeout for Ring Buffer push

static EventGroupHandle_t s_usb_event_group = NULL;
// static RingbufHandle_t s_in_ringbuf_handle = NULL;
static RingbufHandle_t s_out_ringbuf_handle = NULL;
// static SemaphoreHandle_t s_usb_read_mux = NULL;
static SemaphoreHandle_t s_usb_write_mux = NULL;
// static TaskHandle_t s_usb_processing_task_hdl = NULL;

// static portMUX_TYPE s_in_ringbuf_mux = portMUX_INITIALIZER_UNLOCKED;
static portMUX_TYPE s_out_ringbuf_mux = portMUX_INITIALIZER_UNLOCKED;
volatile static int s_in_buffered_data_len = 0;
volatile static int s_out_buffered_data_len = 0;
volatile static usb_connect_type_t s_usb_connect_type = USB_CONNECTED_UNKNOWN;

//////////// End CDC 全局变量 ////////////

//////////// MSC 全局变量 ////////////////

static msc_file_info g_msc_file_lists[MAX_FILE_COUNT];
// static excluding_file_item_t msc_excluding_files[MAX_EXCLUDING_FILE_COUNT];
static uint16_t g_msc_file_count = 0;

//////////// End MSC 全局变量 ////////////

static TaskHandle_t s_usb_task_handle, s_device_task_handle; //, workthread_handle;

static void usb_device_event_cb(const msc_host_event_t *event, void *arg)
{
    switch (event->event)
    {
    case MSC_DEVICE_CONNECTED:
        s_usb_connect_type = USB_CONNECTED_MSC;
        SYS_LOG_INF("MSC device connected");
        sblib_send_event(LIB_EVENT_USBH_MSC, 0, NULL);
        break;
    case MSC_DEVICE_DISCONNECTED:
        s_usb_connect_type = USB_CONNECTED_UNKNOWN;
        SYS_LOG_INF("MSC device disconnected");
        sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL);
        break;
    case CDC_DEVICE_CONNECTED:
        s_usb_connect_type = USB_CONNECTED_CDC;
        SYS_LOG_INF("CDC device connected");
        sblib_send_event(LIB_EVENT_USBH_CDC, 0, NULL);
        break;
    case CDC_DEVICE_DISCONNECTED:
        s_usb_connect_type = USB_CONNECTED_UNKNOWN;
        SYS_LOG_INF("CDC device disconnected");
        sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL);
        break;
    case DFU_DEVICE_CONNECTED:
        s_usb_connect_type = USB_CONNECTED_DFU;
        SYS_LOG_INF("DFU device connected");
        sblib_send_event(LIB_EVENT_USBH_DFU, 0, NULL);
        break;
    case DFU_DEVICE_DISCONNECTED:
        s_usb_connect_type = USB_CONNECTED_UNKNOWN;
        SYS_LOG_INF("DFU device disconnected");
        sblib_send_event(LIB_EVENT_USBH_UNKNOW_DEVICE, 0, NULL);
        break;
    }

    xQueueSend(app_queue, event, 10);
}

// Handles common USB host library events
static void handle_usb_events(void *args)
{
    while (1)
    {
        uint32_t event_flags;
        SYS_LOG_INF("usb_host_lib_handle_events(portMAX_DELAY, &event_flags);");
        usb_host_lib_handle_events(portMAX_DELAY, &event_flags);
        // Release devices once all clients has deregistered
        if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS)
        {
            SYS_LOG_INF("usb_host_device_free_all();");
            usb_host_device_free_all();
            // SYS_LOG_INF("xSemaphoreGive(ready_to_uninstall_usb);");
            // xSemaphoreGive(ready_to_uninstall_usb);
            break;
        }
        // Give ready_to_uninstall_usb semaphore to indicate that USB Host library
        // can be deinitialized, and terminate this task.
        // if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE)
        // {
        //     SYS_LOG_INF("xSemaphoreGive(ready_to_uninstall_usb);");
        //     xSemaphoreGive(ready_to_uninstall_usb);
        // }
    }
    s_usb_task_handle = NULL;
    vTaskDelete(NULL);
}

static void print_device_info(msc_host_device_info_t *info)
{
    const size_t megabyte = 1024 * 1024;
    uint64_t capacity = ((uint64_t)info->sector_size * info->sector_count) / megabyte;

    printf("Device info:\n");
    printf("\t Capacity: %llu MB\n", capacity);
    printf("\t Sector size: %u\n", info->sector_size);
    printf("\t Sector count: %u\n", info->sector_count);
    printf("\t PID: 0x%4X \n", info->idProduct);
    printf("\t VID: 0x%4X \n", info->idVendor);
    wprintf(L"\t iProduct: %S \n", info->iProduct);
    wprintf(L"\t iManufacturer: %S \n", info->iManufacturer);
    wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber);
}

/* ------------------------------- Callbacks -------------------------------- */
static void handle_rx(uint8_t *data, size_t data_len, void *arg)
{
    SYS_LOG_INF("Data received %d bytes", data_len);
    // ESP_LOG_BUFFER_HEXDUMP(data, data_len, ESP_LOG_INFO);

    int write_result = os_pipe_fifo_fill(&s_usb_data.pipe_obj, data, data_len);
    if (write_result != data_len)
    {
        SYS_LOG_WRN("[ERROR]write data to pipe_obj failed, remain: %d bytes, data_len:%d!!",
                    write_result,
                    data_len);
    }

    if (os_pipe_get_empty_size(&s_usb_data.pipe_obj) >= BUFFER_SIZE_BULK_IN)
    {
        cdc_submit_transfer_in(g_cdc_dev);
    }
}

static uint8_t check_file_is_in_excluding_list(const char *filename, uint8_t is_dir, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count)
{
    if (excluding_file_count == 0 || excluding_files == NULL)
    {
        SYS_LOG_INF("excluding file count is empty, break check");
        return 0;
    }

    int source_str_len = strlen(filename);
    int i = 0;
    for (i = 0; i < excluding_file_count; i++)
    {
        const excluding_file_item_t *file_item = &(excluding_files[i]);
        if (is_dir != file_item->is_dir)
        {
            SYS_LOG_INF("src is dir:%d, target is dir:%d", is_dir, file_item->is_dir);
            continue;
        }

        uint8_t is_same = 0;
        if (file_item->compare_type == EXCLUDING_FILE_COMPARE_ALL)
        {
            is_same = strcmp(filename, file_item->filename) == 0;
        }
        else if (file_item->compare_type == EXCLUDING_FILE_COMPARE_PREFIX)
        {
            int len = strlen(file_item->filename);
            if (source_str_len < len)
            {
                // 如果文件名小于要比较的字符串，则忽略检查
                SYS_LOG_INF("SOURCE LEN:%d, target len:%d", source_str_len, len);
                continue;
            }

            SYS_LOG_INF("CHECKING, SRC:%s, target:%s, len:%d", filename, file_item->filename, len);
            is_same = strncmp(filename, file_item->filename, len) == 0;
        }

        if (is_same)
        {
            SYS_LOG_INF("FOUND THE EXCLUD FILE:%s", filename);
            return 1; // 这个文件是要排除的
        }
    }

    return 0;
}

static void list_all_files(const char *dirpath, uint16_t *current_file_index, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count)
{
    // 递归枚举所有文件
    struct dirent *entry;
    struct stat entry_stat;
    char entrypath[MAX_FILE_PATH];
    char entrysize[16];
    const char *entrytype;
    size_t dirpath_len = strlen(dirpath);
    DIR *dir = opendir(dirpath);
    strlcpy(entrypath, dirpath, sizeof(entrypath));
    if (entrypath[dirpath_len - 1] != '/')
    {
        entrypath[dirpath_len] = '/';
        dirpath_len += 1;
    }

    uint16_t *file_index = current_file_index;
    while ((entry = readdir(dir)) != NULL)
    {
        entrytype = (entry->d_type == DT_DIR ? "directory" : "file");

        strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len);
        if (entry->d_type != DT_DIR)
        {
            if (check_file_is_in_excluding_list(entry->d_name, 0, excluding_files, excluding_file_count))
            {
                continue;
            }

            SYS_LOG_INF("file path:%s", entrypath);
            if (esp_vfs_stat(__getreent(), entrypath, &entry_stat) == -1)
            {
                SYS_LOG_ERR("Failed to stat %s : %s", entrytype, entry->d_name);
                continue;
            }

            sprintf(entrysize, "%ld", entry_stat.st_size);
            SYS_LOG_INF("Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize);

            msc_file_info *file_info = &(g_msc_file_lists[*file_index]);
            strlcpy(file_info->file_path, entrypath, MAX_FILE_PATH);
            file_info->file_size = entry_stat.st_size;
            *file_index = *file_index + 1;
        }
        else
        {
            if (check_file_is_in_excluding_list(entry->d_name, 1, excluding_files, excluding_file_count))
            {
                continue;
            }

            // 检查文件名是否以.号开始，是的话则忽略这个文件夹
            SYS_LOG_INF("ITEM NAME:%s", entry->d_name);
            if (strncmp(entry->d_name, "SPOTLI~", 7) == 0)
            {
                // 这个文件夹是MAC系统自动生成的，用于spotlight搜索的索引文件夹，忽略它，否则会导致opendir失败
                continue;
            }
            else
            {
                SYS_LOG_INF("ENTER SUB DIR:%s", entrypath);
                list_all_files(entrypath, file_index, excluding_files, excluding_file_count);
            }
        }
    }
    closedir(dir);
}

static void handle_device_events(void *args)
{
    msc_host_event_t app_event;
    while (1)
    {
        SYS_LOG_INF("xQueueReceive(app_queue, &app_event, portMAX_DELAY);");
        xQueueReceive(app_queue, &app_event, portMAX_DELAY);

        switch (app_event.event)
        {
        case MSC_DEVICE_CONNECTED:
        {
            uint8_t device_address = app_event.device.address;
            ESP_ERROR_CHECK(msc_host_install_device(device_address, &g_connected_usb_device));
            msc_host_print_descriptors(g_connected_usb_device);
            msc_host_device_info_t info;
            ESP_ERROR_CHECK(msc_host_get_device_info(g_connected_usb_device, &info));
            print_device_info(&info);
            const esp_vfs_fat_mount_config_t mount_config = {
                .format_if_mount_failed = false,
                .max_files = 1,
                .allocation_unit_size = 1024,
            };
            ESP_ERROR_CHECK(msc_host_vfs_register(g_connected_usb_device, "/usb", &mount_config, &vfs_handle));

            for (int i = 0; i < g_msc_file_count; i++)
            {
                msc_file_info *file_info = &g_msc_file_lists[i];

                SYS_LOG_INF("file path: %s, file_size:%d", file_info->file_path, file_info->file_size);
            }

            g_usb_status = USBPORT_STATUS_MSC;
        }
        break;

        case MSC_DEVICE_DISCONNECTED:
            ESP_ERROR_CHECK(msc_host_vfs_unregister(vfs_handle));
            vfs_handle = NULL;
            ESP_ERROR_CHECK(msc_host_uninstall_device(g_connected_usb_device));
            g_connected_usb_device = NULL;
            g_usb_status = USBPORT_STATUS_NO_CONNECTION;
            break;

        case CDC_DEVICE_CONNECTED:
        {
            SYS_LOG_INF("cdc device connected");

            // SYS_LOG_INF("Installing CDC-ACM driver");
            // ESP_ERROR_CHECK(cdc_acm_host_install(NULL));

            // cdc_acm_dev_hdl_t cdc_dev;
            const cdc_acm_host_device_config_t dev_config = {
                .connection_timeout_ms = 5000,
                .out_buffer_size = 64,
                .user_arg = NULL,
                .event_cb = NULL,
                .data_cb = handle_rx};
            cdc_host_open(app_event.vendor_id, app_event.product_id, 0, &dev_config, &g_cdc_dev);
            assert(g_cdc_dev);
            cdc_host_desc_print(g_cdc_dev);
            g_usb_status = USBPORT_STATUS_CDC;
            // g_connected_usb_device = cdc_dev;
        }
        break;
        case CDC_DEVICE_DISCONNECTED:
            SYS_LOG_INF("cdc device dconnected");
            cdc_host_close(g_cdc_dev);
            g_usb_status = USBPORT_STATUS_NO_CONNECTION;
            break;
        case DFU_DEVICE_CONNECTED:
            SYS_LOG_INF("DFU DEVICE CONNECTED");
            const cdc_acm_host_device_config_t dev_config = {
                .connection_timeout_ms = 5000,
                .out_buffer_size = 64,
                .user_arg = NULL,
                .event_cb = NULL,
                .data_cb = handle_rx};
            dfu_host_open(app_event.vendor_id, app_event.product_id, 0, &dev_config, &g_cdc_dev);

            g_usb_status = USBPORT_STATUS_DFU;
            break;
        case DFU_DEVICE_DISCONNECTED:
            SYS_LOG_INF("DFU DEVICE DISCONNECTED");
            dfu_host_close(g_cdc_dev);
            g_usb_status = USBPORT_STATUS_NO_CONNECTION;
            break;
        default:
            assert(0);
            break;
        }

        /* code */
    }

    vTaskDelete(NULL);
}

////////////////////////////////////////////////
//////////// CDC设备透传的相关的函数 //////////////
////////////////////////////////////////////////

static bool _if_device_ready()
{
    if (!s_usb_event_group)
        return false;
    return xEventGroupGetBits(s_usb_event_group) & CDC_DEVICE_READY_BIT;
}

static bool _cdc_driver_is_init(void)
{
    if (s_usb_event_group == NULL)
    {
        return false;
    }

    return true;
}

static esp_err_t usb_out_ringbuf_push(const uint8_t *buf, size_t write_bytes, TickType_t xTicksToWait)
{
    int res =
        xRingbufferSend(s_out_ringbuf_handle, buf, write_bytes, xTicksToWait);

    if (res != pdTRUE)
    {
        SYS_LOG_WRN("The out buffer is too small, the data has been lost %u", write_bytes);
        return ESP_FAIL;
    }

    portENTER_CRITICAL(&s_out_ringbuf_mux);
    s_out_buffered_data_len += write_bytes;
#ifdef CONFIG_CDC_USE_TRACE_FACILITY
    s_ringbuf_out_max = s_out_buffered_data_len > s_ringbuf_out_max ? s_out_buffered_data_len : s_ringbuf_out_max;
#endif
    portEXIT_CRITICAL(&s_out_ringbuf_mux);
    return ESP_OK;
}

int usbh_cdc_write_bytes(const uint8_t *buf, size_t length)
{
    SYS_LOG_INF("write data to cdc devi11111");
    CDC_CHECK(buf != NULL, "invalid args", -1);
    int tx_data_size = 0;

    if (_cdc_driver_is_init() == false)
    {
        SYS_LOG_INF("CDC Driver not installed");
        return -1;
    }

    if (_if_device_ready() == false)
    {
        SYS_LOG_INF("Device not connected or not ready");
        return -1;
    }

    SYS_LOG_INF("write data to cdc devie2222");
    xSemaphoreTake(s_usb_write_mux, portMAX_DELAY);
    esp_err_t ret = usb_out_ringbuf_push(buf, length, pdMS_TO_TICKS(TIMEOUT_USB_RINGBUF_MS));

    if (ret != ESP_OK)
    {
        xSemaphoreGive(s_usb_write_mux);
        SYS_LOG_DBG("Write pipe_obj failed");
        return -1;
    }

    tx_data_size = length;
    xSemaphoreGive(s_usb_write_mux);
    return tx_data_size;
}

static int _usbhost_port_write(sb_data_port_t *port, const void *data, uint32_t size)
{
    int result = cdc_write_bytes(data, size);
    return result;
}

static int _usbhost_port_read(sb_data_port_t *port, void *buffer, uint32_t length)
{
    if (os_pipe_is_valid(&s_usb_data.pipe_obj))
    {
        int ret = os_pipe_fifo_read(&s_usb_data.pipe_obj, buffer, length);
        if (ret > 0 && os_pipe_get_empty_size(&s_usb_data.pipe_obj) >= BUFFER_SIZE_BULK_IN)
        {
            cdc_submit_transfer_in(g_cdc_dev);
        }

        SYS_LOG_INF("Data readed %d bytes", ret);

        return ret;
    }
    else
    {
        return -1;
    }
}

static bool s_is_started = false;
static int _usbhost_start(sb_data_port_t *port)
{
    s_is_started = true;
    return 0;
}

static int _usbhost_stop(sb_data_port_t *port)
{
    s_is_started = false;
    return 0;
}

static bool _usbhost_is_started(sb_data_port_t *port)
{
    return s_is_started;
}

static uint32_t _usbhost_get_rx_length(sb_data_port_t *port)
{
    return os_pipe_get_valid_size(&s_usb_data.pipe_obj);
}

static sb_data_port_vtable_t const usbhost_port_vtable = {
    .start = _usbhost_start,                 // 由具体驱动实现的，以达到节省资源为主要目的，启动数据接口
    .stop = _usbhost_stop,                   // 由具体驱动实现的，以达到节省资源为主要目的，关闭数据接口
    .write = _usbhost_port_write,            // 由具体驱动实现的，写数据到对应的接口。
    .read = _usbhost_port_read,              // 由具体驱动实现的，从数据接口中读取已缓存的数据。
    .is_started = _usbhost_is_started,       // 由具体驱动实现的，获取当前数据接口是否可用（是否已启动）
    .get_rx_length = _usbhost_get_rx_length, // 由具体驱动实现的，获取当前数据接口的本次可读长度
};

//////////// CDC设备透传的相关的函数结束 ///////////

////////////////////////////////////////////////
//////////// STM32固件升级相关的函数 //////////////
////////////////////////////////////////////////

// esp_err_t _usbh_stm32_control_transfer(uint8_t direction,
//                                        uint8_t request,
//                                        uint16_t value,
//                                        uint16_t interface,
//                                        uint16_t length,
//                                        uint8_t *packet_data,
//                                        uint8_t *out_buffer,
//                                        uint16_t out_buffer_size,
//                                        uint16_t *actual_result_size)
// {
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     return _usb_control_transfer(g_pipe_hdl_dflt, direction, request, value, interface, length, packet_data, out_buffer, out_buffer_size, actual_result_size);
//     // }

//     return ESP_FAIL;
// }

// esp_err_t _usbh_stm32_control_transfer_ex(uint8_t direction,
//                                           uint8_t request,
//                                           uint16_t value,
//                                           uint16_t interface,
//                                           uint16_t length,
//                                           uint8_t *packet_data,
//                                           uint8_t *out_buffer,
//                                           uint16_t out_buffer_size,
//                                           uint16_t *actual_result_size,
//                                           uint16_t timeout)
// {
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     return _usb_control_transfer_ex(g_pipe_hdl_dflt,
//     //                                     direction,
//     //                                     request,
//     //                                     value,
//     //                                     interface,
//     //                                     length,
//     //                                     packet_data,
//     //                                     out_buffer,
//     //                                     out_buffer_size,
//     //                                     actual_result_size,
//     //                                     timeout);
//     // }

//     return ESP_FAIL;
// }

// esp_err_t _usbh_stm32_try_read_ob(uint16_t ob_data_size)
// {
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     return _usb_try_read_ob(g_pipe_hdl_dflt, ob_data_size);
//     // }

//     return ESP_FAIL;
// }

// esp_err_t _usbh_stm32_unprotect()
// {
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     return _usb_unprotect(g_pipe_hdl_dflt);
//     // }

//     return ESP_FAIL;
// }

// esp_err_t _usbh_stm32_leave_dfu()
// {
//     return ESP_OK;
//     //     if (g_pipe_hdl_dflt == NULL) {
//     //         return ESP_FAIL;
//     //     }

//     //     // _usb_control_transfer_ex(pipe_handle,
//     //     //                                 USB_BM_REQUEST_TYPE_DIR_IN,
//     //     //                                 STM32_DFU_REQUEST_GETSTATUS,
//     //     //                                 0,
//     //     //                                 0,
//     //     //                                 6,
//     //     //                                 0,
//     //     //                                 out_result_data,
//     //     //                                 6,
//     //     //                                 NULL,
//     //     //                                 timeout);

//     //     uint8_t direction = USB_BM_REQUEST_TYPE_DIR_IN;
//     //     uint8_t request = STM32_DFU_REQUEST_GETSTATUS;
//     //     uint16_t value = 0;
//     //     uint16_t interface = 0;
//     //     uint16_t length = 6;
//     //     uint8_t *packet_data = NULL;
//     //     uint8_t *out_buffer = NULL;
//     //     uint16_t out_buffer_size = 0;
//     //     uint16_t *actual_result_size = NULL;
//     //     uint16_t timeout = 500;

//     //     CDC_CHECK(g_pipe_hdl_dflt != NULL, "g_pipe_hdl_dflt can't be NULL", ESP_ERR_INVALID_ARG);
//     //     // malloc URB for default control
//     //     uint16_t packet_data_size = ENUM_CTRL_TRANSFER_MAX_LEN;
//     //     if (length > packet_data_size) {
//     //         packet_data_size = length;
//     //     }
//     //     urb_t *urb_ctrl = _usb_urb_alloc(0, sizeof(usb_setup_packet_t) + packet_data_size, NULL);
//     //     CDC_CHECK(urb_ctrl != NULL, "alloc urb failed", ESP_ERR_NO_MEM);

//     //     usb_setup_packet_t *setup_packet = (usb_setup_packet_t *)urb_ctrl->transfer.data_buffer;
//     //     if (direction == USB_BM_REQUEST_TYPE_DIR_IN) {
//     //         setup_packet->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
//     //         setup_packet->bRequest = request;
//     //         setup_packet->wValue = value;
//     //         setup_packet->wIndex = interface;
//     //         setup_packet->wLength = length;
//     //         urb_ctrl->transfer.num_bytes = sizeof(usb_setup_packet_t) + length;
//     //     } else if (direction == USB_BM_REQUEST_TYPE_DIR_OUT) {
//     //         setup_packet->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE;
//     //         setup_packet->bRequest = request;
//     //         setup_packet->wValue = value;
//     //         setup_packet->wIndex = interface;
//     //         setup_packet->wLength = length;
//     //         memcpy(((uint8_t *)setup_packet) + sizeof(usb_setup_packet_t), packet_data, length);
//     //         urb_ctrl->transfer.num_bytes = sizeof(usb_setup_packet_t) + length;
//     //     }

//     //     // Enqueue it
//     //     esp_err_t ret = hcd_urb_enqueue(g_pipe_hdl_dflt, urb_ctrl);
//     //     CDC_CHECK_GOTO(ESP_OK == ret, "urb enqueue failed", free_urb_);
//     //     SYS_LOG_INF("urb request timeout:%d ms, and becuase it used for leave dfu, so dont wait response", timeout);

//     //     goto free_urb_;

//     // free_urb_:
//     //     _usb_pipe_flush(g_pipe_hdl_dflt, 1);
//     //     _usb_urb_free(urb_ctrl);
//     //     return ret;
// }

// uint16_t usbh_stm32_get_transfer_block_size()
// {
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     usb_function_desc_packet_t function_desc_packet;
//     //     esp_err_t ret = _usb_get_function_descriptors(g_pipe_hdl_dflt, 0, &function_desc_packet);
//     //     if (ret != ESP_OK) {
//     //         return 2048;
//     //     } else {
//     //         return function_desc_packet.wTransferSize;
//     //     }
//     // }

//     return 0;
// }

// esp_err_t usbh_stm32_clear_status()
// {
//     // // return _usbh_
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     return _usb_clear_status(g_pipe_hdl_dflt);
//     // }

//     return ESP_FAIL;
// }

// esp_err_t _usbh_stm32_load_address(uint32_t address)
// {
//     // if (g_pipe_hdl_dflt != NULL) {
//     //     return _usb_load_address(g_pipe_hdl_dflt, address);
//     // }

//     return ESP_FAIL;
// }

//////////// STM32固件升级相关的函数结束 //////////////

// static TaskHandle_t s_usb_task_handle, s_device_task_handle; //, workthread_handle;

int usbport_init(void)
{
    SYS_LOG_INF("usbport_init");
    if (s_port.vtable)
    {
        SYS_LOG_WRN("repeated initialize");
        return -1;
    }

    s_port.vtable = &usbhost_port_vtable;
    s_port.data = &s_usb_data;

    memset(&s_usb_data, 0, sizeof(__usb_data_t));
    os_pipe_create(&s_usb_data.pipe_obj, 1024 * 2);

    // if (ready_to_uninstall_usb == NULL)
    // {
    //     ready_to_uninstall_usb = xSemaphoreCreateBinary();
    // }

    app_queue = xQueueCreate(3, sizeof(msc_host_event_t));
    assert(app_queue);

    static usb_host_config_t const host_config = {
        .skip_phy_setup = false,
        .intr_flags = ESP_INTR_FLAG_LEVEL1,
    };
    ESP_ERROR_CHECK(usb_host_install(&host_config));

    if (s_usb_task_handle == NULL)
    {
        xTaskCreatePinnedToCore(handle_usb_events, "usb_events", 4096, NULL, SBTASK_PRIORITY_USB_HOST, &s_usb_task_handle, SBTASK_CORE_INDEX_USB_HOST);
        assert(s_usb_task_handle);
    }
    if (s_device_task_handle == NULL)
    {
        xTaskCreatePinnedToCore(handle_device_events, "device_events", 4096, NULL, SBTASK_PRIORITY_USB_DEVICE, &s_device_task_handle, SBTASK_CORE_INDEX_USB_DEVICE);
        assert(s_device_task_handle);
    }

    const msc_host_driver_config_t msc_config = {
        .create_backround_task = true,
        .task_priority = SBTASK_PRIORITY_USB_MSC,
        .stack_size = 2048 * 2,
        .callback = usb_device_event_cb,
        .core_id = 0};
    ESP_ERROR_CHECK(msc_host_install(&msc_config));

    return 0;
}

void usbport_deinit(void)
{
    SYS_LOG_INF("usbport_deinit");
    if (s_port.vtable == NULL)
    {
        SYS_LOG_WRN("usb host not initialized");
        return;
    }

    if (g_connected_usb_device)
    {
        if (vfs_handle)
        {
            msc_host_vfs_unregister(vfs_handle);
            vfs_handle = NULL;
        }
        msc_host_uninstall_device(g_connected_usb_device);
        g_connected_usb_device = NULL;
    }

    if (g_cdc_dev)
    {
        cdc_host_close(g_cdc_dev);
        g_cdc_dev = NULL;
    }

    ESP_ERROR_CHECK(msc_host_uninstall());

    vTaskDelay(pdMS_TO_TICKS(100));

    // if (s_device_task_handle)
    // {
    //     vTaskDelete(s_device_task_handle);
    //     s_device_task_handle = NULL;
    // }

    // if (s_usb_task_handle)
    // {
    //     vTaskDelete(s_usb_task_handle);
    //     s_usb_task_handle = NULL;
    // }

    ESP_ERROR_CHECK(usb_host_uninstall());

    if (app_queue)
    {
        vQueueDelete(app_queue);
        app_queue = NULL;
    }

    // if (ready_to_uninstall_usb)
    // {
    //     vSemaphoreDelete(ready_to_uninstall_usb);
    //     ready_to_uninstall_usb = NULL;
    // }

    if (os_pipe_is_valid(&s_usb_data.pipe_obj))
    {
        os_pipe_delete(&s_usb_data.pipe_obj);
    }

    s_port.vtable = NULL;
}

sb_data_port_t *usbport_bind(os_work_t *rx_resume_work)
{
    if (s_port.data == NULL)
    {
        SYS_LOG_WRN("usb host not initialized");
        return NULL;
    }

    __usb_data_t *usb_data = s_port.data;
    usb_data->rx_resume_work = rx_resume_work;

    os_pipe_regist(&usb_data->pipe_obj, rx_resume_work, 0);

    return &s_port;
}

void usbport_unbind(sb_data_port_t *port)
{
    if (port == NULL)
    {
        SYS_LOG_WRN("usb host not initialized");
        return;
    }

    __usb_data_t *usb_data = port->data;

    os_pipe_unregist(&usb_data->pipe_obj);

    usb_data->rx_resume_work = NULL;
}

usbport_status_e usbport_get_state(void)
{
    return g_usb_status;
}

msc_file_info *msc_get_file_list(uint16_t *out_file_count, const excluding_file_item_t *excluding_files, uint8_t excluding_file_count)
{
    g_msc_file_count = 0;
    list_all_files("/usb/", &g_msc_file_count, excluding_files, excluding_file_count);

    return msc_get_cached_file_list(out_file_count);
}

msc_file_info *msc_get_cached_file_list(uint16_t *out_file_count)
{
    if (out_file_count)
    {
        *out_file_count = g_msc_file_count;
    }
    return g_msc_file_lists;
}

usb_connect_type_t usbport_get_usb_type(void)
{
    return s_usb_connect_type;
}
