#include "Touch.hpp"
#include "driver/i2c_master.h"
#include "esp_log.h"
#include "esp_lcd_touch_gt911.h"
#include "WidgetManager.hpp"

// Common display resolutions, used for touch dimensions
#define LCD_H_RES 800
#define LCD_V_RES 1280

// Touch config (GT911)
#define TOUCH_I2C_SDA 7
#define TOUCH_I2C_SCL 8
#define TOUCH_INT_GPIO 3
#define TOUCH_RST_GPIO 2
#define TOUCH_I2C_FREQ_HZ 400000

Touch::Touch() : touch_handle(nullptr) {}

void Touch::init() {
    // --- I2C Bus Config ---
    i2c_master_bus_config_t i2c_bus_cfg = {};
    i2c_bus_cfg.i2c_port = I2C_NUM_0;
    i2c_bus_cfg.sda_io_num = static_cast<gpio_num_t>(TOUCH_I2C_SDA);
    i2c_bus_cfg.scl_io_num = static_cast<gpio_num_t>(TOUCH_I2C_SCL);
    i2c_bus_cfg.clk_source = I2C_CLK_SRC_DEFAULT;
    i2c_bus_cfg.glitch_ignore_cnt = 7;
    i2c_bus_cfg.flags.enable_internal_pullup = true;

    i2c_master_bus_handle_t i2c_bus = NULL;
    ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus));

    // --- Touch Panel IO Config ---
    esp_lcd_panel_io_handle_t touch_io = NULL;
    esp_lcd_panel_io_i2c_config_t touch_io_cfg = {};
    touch_io_cfg.dev_addr = 0x5D; // Default GT911 address
    touch_io_cfg.control_phase_bytes = 1;
    touch_io_cfg.dc_bit_offset = 0;
    touch_io_cfg.lcd_cmd_bits = 16;
    touch_io_cfg.flags.disable_control_phase = true;
    touch_io_cfg.scl_speed_hz = TOUCH_I2C_FREQ_HZ;
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(i2c_bus, &touch_io_cfg, &touch_io));

    // --- Touch Device Config ---
    esp_lcd_touch_config_t touch_cfg = {};
    touch_cfg.x_max = LCD_H_RES;
    touch_cfg.y_max = LCD_V_RES;
    touch_cfg.rst_gpio_num = static_cast<gpio_num_t>(TOUCH_RST_GPIO);
    touch_cfg.int_gpio_num = static_cast<gpio_num_t>(TOUCH_INT_GPIO);
    touch_cfg.levels.reset = 0;
    touch_cfg.levels.interrupt = 0;
    touch_cfg.flags.swap_xy = 1;
    touch_cfg.flags.mirror_x = 1;
    touch_cfg.flags.mirror_y = 0;

    ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(touch_io, &touch_cfg, &this->touch_handle));
}

esp_lcd_touch_handle_t Touch::getTouchHandle() const {
    return this->touch_handle;
}

void Touch::lv_indev_read_cb(lv_indev_t *indev, lv_indev_data_t *data)
{
    
    Touch* self = static_cast<Touch*>(lv_indev_get_user_data(indev));
    if (!self) {
        data->state = LV_INDEV_STATE_RELEASED;
        return;
    }

    uint16_t x[1], y[1];
    uint8_t touch_cnt = 0;

    esp_lcd_touch_read_data(self->getTouchHandle());
    if (esp_lcd_touch_get_coordinates(self->getTouchHandle(), x, y, NULL, &touch_cnt, 1) && touch_cnt > 0) {
        data->point.x = x[0];
        data->point.y = y[0];
        data->state = LV_INDEV_STATE_PRESSED;
        // TEMP: Disabled to test if this causes the freeze
        // WidgetManager::instance().onUserActivity();
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}
