#include "gpio.h"
#include "esp_lvgl_port.h"
#include "esp_lcd_st77916.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lcd.h"
#include "esp_lcd_touch_cst816s.h"
#include "unity.h"
#include "unity_test_runner.h"
#include <string.h>
#include "esp_heap_caps.h"

static lv_disp_t * disp_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_touch_handle_t touch_handle;
static esp_lcd_panel_io_handle_t tp_io_handle = NULL;


void lcd_init(){
    const spi_bus_config_t buscfg = ST77916_PANEL_BUS_QSPI_CONFIG(PIN_LCD_CLK,
                                                                    PIN_LCD_D0,
                                                                    PIN_LCD_D1,
                                                                    PIN_LCD_D2,
                                                                    PIN_LCD_D3,
                                                                    LCD_HIGH * 80 * sizeof(uint16_t));
    spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);

    // 自定义IO配置，提升SPI时钟从40MHz到80MHz
    esp_lcd_panel_io_spi_config_t io_config = ST77916_PANEL_IO_QSPI_CONFIG(PIN_LCD_CS, NULL, NULL);
    io_config.pclk_hz = 80 * 1000 * 1000;  // 提升到80MHz（最大值）
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI_LCD_HOST, &io_config, &io_handle));
    const st77916_vendor_config_t vendor_config = {
        .flags = {
            .use_qspi_interface = 1,
        },
    };
    const esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_LCD_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
        .vendor_config = &vendor_config,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_st77916(io_handle, &panel_config, &panel_handle));
    esp_lcd_panel_reset(panel_handle);
    esp_lcd_panel_init(panel_handle);

    // 清空LCD GRAM，避免显示上次关机时的残留画面
    // 创建黑色缓冲区填充整个屏幕
    size_t clear_buffer_size = LCD_WID * 40;  // 每次清除40行
    uint16_t *clear_buffer = heap_caps_malloc(clear_buffer_size * sizeof(uint16_t), MALLOC_CAP_DMA);
    if (clear_buffer) {
        memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t));  // 填充黑色(0x0000)

        // 分批填充整个屏幕（避免一次性分配大内存）
        for (int y = 0; y < LCD_HIGH; y += 40) {
            int lines = (y + 40 > LCD_HIGH) ? (LCD_HIGH - y) : 40;
            esp_lcd_panel_draw_bitmap(panel_handle, 0, y, LCD_WID, y + lines, clear_buffer);
        }

        heap_caps_free(clear_buffer);
        ESP_LOGI(LCD_TAG, "LCD GRAM cleared (black filled)");
    } else {
        ESP_LOGE(LCD_TAG, "Failed to allocate clear buffer");
    }

    esp_lcd_panel_disp_on_off(panel_handle, true);
}

// 初始化触摸控制器
void touch_init(){
    const esp_lcd_touch_config_t tp_cfg = {
        .x_max = LCD_WID,
        .y_max = LCD_HIGH,
        .rst_gpio_num = PIN_TP_RST,
        .int_gpio_num = PIN_TP_INT,
        .levels = {
            .reset = 0,// 重置电平
            .interrupt = 0,// 中断电平
        },
        .flags = {
            .swap_xy = false,// 交换XY轴
            .mirror_x = false,// 水平镜像
            .mirror_y = false,// 垂直镜像
        },
    };
    const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
    esp_err_t err = esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_MASTER_NUM, &tp_io_config, &tp_io_handle);
    if (err != ESP_OK) {
        ESP_LOGE(LCD_TAG, "Failed to create I2C IO for touch: %s", esp_err_to_name(err));
        return;
    }
    err = esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &touch_handle);
    if (err != ESP_OK) {
        ESP_LOGE(LCD_TAG, "Failed to create touch handle: %s", esp_err_to_name(err));
        return;
    }
    ESP_LOGI(LCD_TAG, "Touch controller initialized successfully");
}

// 初始化LVGL显示和触摸
void lvgl_lcd_init(){
    const lvgl_port_cfg_t lvgl_cfg = {
        .task_priority = 4,
        .task_stack = 8192,
        .task_affinity = -1,
        .task_max_sleep_ms = 500,
        .timer_period_ms = 5
    };
    lvgl_port_init(&lvgl_cfg);
    
    #define LVGL_DRAW_BUF_LINES 120
    size_t buffer_size = LCD_WID * LVGL_DRAW_BUF_LINES;

    ESP_LOGI(LCD_TAG, "LVGL buffer size: %d bytes (W: %d, Lines: %d)",
             buffer_size * 2, LCD_WID, LVGL_DRAW_BUF_LINES);

    const lvgl_port_display_cfg_t disp_cfg = {
        .io_handle = io_handle,
        .panel_handle = panel_handle,
        .buffer_size = buffer_size,
        .double_buffer = true,
        .hres = LCD_WID,
        .vres = LCD_HIGH,
        .monochrome = false,// 单色显示
        .rotation = {
            .swap_xy = false,// 交换XY轴
            .mirror_x = false,// 水平镜像
            .mirror_y = false,// 垂直镜像
        },
        .flags = {
            .buff_dma = false,
            .buff_spiram = true,// PSRAM 120行大缓冲，每帧仅3次flush，GIF最流畅
        }
    };
    disp_handle = lvgl_port_add_disp(&disp_cfg);
    if (touch_handle != NULL) {
        lvgl_port_touch_cfg_t touch_cgf = {
            .disp = disp_handle,
            .handle = touch_handle,
        };
        lvgl_port_add_touch(&touch_cgf);
        ESP_LOGI(LCD_TAG, "Touch controller added to LVGL");
    } else {
        ESP_LOGE(LCD_TAG, "Touch handle is NULL, skipping touch initialization");
    }
}
 
void get_touch(uint16_t* touchx,uint16_t* touchy){
    if (touch_handle == NULL) {
        ESP_LOGE(LCD_TAG, "Touch handle is NULL, cannot get touch data");
        *touchx = 0;
        *touchy = 0;
        return;
    }
    uint8_t max = 1;
    max = touch_handle->data.points;
    *touchx = touch_handle->data.coords[0].x;
    *touchy = touch_handle->data.coords[0].y;
    printf("%x\n",max);
}

// 清空LCD GRAM为黑色（用于低功耗熄屏前，避免残影）
void lcd_clear_screen_black(void) {
    if (panel_handle == NULL) {
        ESP_LOGE(LCD_TAG, "Panel handle is NULL, cannot clear screen");
        return;
    }

    size_t clear_buffer_size = LCD_WID * 40;  // 每次清除40行
    uint16_t *clear_buffer = heap_caps_malloc(clear_buffer_size * sizeof(uint16_t), MALLOC_CAP_DMA);
    if (clear_buffer) {
        memset(clear_buffer, 0, clear_buffer_size * sizeof(uint16_t));  // 填充黑色(0x0000)

        // 分批填充整个屏幕
        for (int y = 0; y < LCD_HIGH; y += 40) {
            int lines = (y + 40 > LCD_HIGH) ? (LCD_HIGH - y) : 40;
            esp_lcd_panel_draw_bitmap(panel_handle, 0, y, LCD_WID, y + lines, clear_buffer);
        }

        heap_caps_free(clear_buffer);
        ESP_LOGI(LCD_TAG, "LCD GRAM cleared to black (for low power mode)");
    } else {
        ESP_LOGE(LCD_TAG, "Failed to allocate clear buffer");
    }
}