#include "cst816x.h"
#include "board.h"
#include "application.h"
#include "display.h"
#include "assets/lang_config.h"
#include "wifi_board.h"
#include "power_save_timer.h"
#include "codecs/es8311_audio_codec.h"
#include <algorithm>  // 用于std::max/std::min

#define TAG "Cst816x"

const Cst816x::TouchThresholdConfig& Cst816x::getThresholdConfig(int x, int y) {
    for (const auto& config : TOUCH_THRESHOLD_TABLE) {
        if (config.x == x && config.y == y) {
            return config;
        }
    }
    return DEFAULT_THRESHOLD;
}

Cst816x::Cst816x(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
    uint8_t chip_id = ReadReg(0xA7);
    ESP_LOGI(TAG, "Get CST816x chip ID: 0x%02X", chip_id);
    read_buffer_ = new uint8_t[6];
}

Cst816x::~Cst816x() {
    if (read_buffer_ != nullptr) {
        delete[] read_buffer_;
        read_buffer_ = nullptr;
    }
}

int64_t Cst816x::getCurrentTimeUs() {
    struct timeval tv;
    gettimeofday(&tv, nullptr);  
    return (int64_t)tv.tv_sec * 1000000L + tv.tv_usec;
}

void Cst816x::UpdateTouchPoint() {
    ReadRegs(0x02, read_buffer_, 6);
    tp_.num = read_buffer_[0] & 0x0F;
    tp_.x = ((read_buffer_[1] & 0x0F) << 8) | read_buffer_[2];
    tp_.y = ((read_buffer_[3] & 0x0F) << 8) | read_buffer_[4];
    memset(read_buffer_, 0, 6);
}

void Cst816x::resetTouchCounters() {
    is_touching_ = false;
    touch_start_time_ = 0;
    last_release_time_ = 0;
    click_count_ = 0;
    long_press_started_ = false;

    is_volume_long_pressing_ = false;
    volume_long_press_dir_ = 0;
    last_volume_adjust_time_ = 0;
}

void Cst816x::touchpad_daemon(void* arg) {
    Cst816x* cst816x = static_cast<Cst816x*>(arg);  
    auto& board = Board::GetInstance();             
    auto codec = board.GetAudioCodec();             
    auto display = board.GetDisplay();             

    while (1) {
        cst816x->UpdateTouchPoint();
        auto& tp = cst816x->GetTouchPoint(); 
        int64_t current_time = cst816x->getCurrentTimeUs(); 

        const auto& config = cst816x->getThresholdConfig(tp.x, tp.y);
        if (tp.num > 0) {
            ESP_LOGD(TAG, "Touch at (%d,%d) → SingleThresh:%lldms, DoubleWindow:%lldms, LongThresh:%lldms",
                tp.x, tp.y,
                config.single_click_thresh_us / 1000,
                config.double_click_window_us / 1000,
                config.long_press_thresh_us / 1000);
        }

        TouchEvent current_event;  
        bool event_detected = false;

        if (tp.num > 0 && !cst816x->is_touching_) {
            cst816x->is_touching_ = true;
            cst816x->touch_start_time_ = current_time;  
            cst816x->long_press_started_ = false;
        }
        else if (tp.num > 0 && cst816x->is_touching_) {
            if (!cst816x->long_press_started_ && 
                (current_time - cst816x->touch_start_time_ >= config.long_press_thresh_us)) {
                current_event = {TouchEventType::LONG_PRESS_START, tp.x, tp.y};
                event_detected = true;
                cst816x->long_press_started_ = true;
            }
        }
        else if (tp.num == 0 && cst816x->is_touching_) {
            cst816x->is_touching_ = false;
            int64_t touch_duration = current_time - cst816x->touch_start_time_;
            cst816x->last_release_time_ = current_time;
            if (cst816x->long_press_started_) {
                current_event = {TouchEventType::LONG_PRESS_END, tp.x, tp.y};
                event_detected = true;
            }
            else if (touch_duration <= config.single_click_thresh_us) {
                cst816x->click_count_++;
            }
        }
        else if (tp.num == 0 && !cst816x->is_touching_) {
            if (cst816x->click_count_ > 0 && 
                (current_time - cst816x->last_release_time_ >= config.double_click_window_us)) {
                if (cst816x->click_count_ == 2) {
                    current_event = {TouchEventType::DOUBLE_CLICK, tp.x, tp.y};
                    event_detected = true;
                }
                else if (cst816x->click_count_ == 1) {
                    current_event = {TouchEventType::SINGLE_CLICK, tp.x, tp.y};
                    event_detected = true;
                }
                cst816x->click_count_ = 0; 
            }
        }

        if (event_detected) {
            if (current_event.y == 600 && (current_event.x == 20 || current_event.x == 40 || current_event.x == 60)) {
                switch (current_event.type) {
                    case TouchEventType::SINGLE_CLICK:
                        if (current_event.x == 40) {
                            board.SetPowerSaveLevel(PowerSaveLevel::PERFORMANCE);
                            auto& app = Application::GetInstance();
                            if (app.GetDeviceState() == kDeviceStateStarting) {
                                auto& wifi_board = static_cast<WifiBoard&>(Board::GetInstance());
                                wifi_board.EnterWifiConfigMode();
                                return;
                            }
                            app.ToggleChatState();  
                        } else if (current_event.x == 20) {     // 20,600 单击：音量+
                            int current_vol = codec->output_volume();
                            int new_vol = current_vol + 10;
                            new_vol = (new_vol >= ES8311_VOL_MAX) ? ES8311_VOL_MAX : new_vol;
                            ESP_LOGI(TAG, "current_vol, new_vol(%d, %d)", current_vol, new_vol);
                            codec->EnableOutput(true);
                            codec->SetOutputVolume(new_vol);
                            display->ShowNotification(Lang::Strings::VOLUME + std::to_string(new_vol));
                        } else if (current_event.x == 60) {     // 60,600 单击：音量-
                            int current_vol = codec->output_volume();
                            int new_vol = current_vol - 10;
                            new_vol = (new_vol <= ES8311_VOL_MIN) ? ES8311_VOL_MIN : new_vol;
                            ESP_LOGI(TAG, "current_vol, new_vol(%d, %d)", current_vol, new_vol);
                            codec->EnableOutput(true);
                            codec->SetOutputVolume(new_vol);
                            display->ShowNotification(Lang::Strings::VOLUME + std::to_string(new_vol));
                        }
                        break;

                    case TouchEventType::DOUBLE_CLICK:
                        ESP_LOGI(TAG, "Double click detected at (%d, %d)", current_event.x, current_event.y);
                        break;

                    case TouchEventType::LONG_PRESS_START:
                        ESP_LOGI(TAG, "Long press started at (%d, %d) → Start volume adjust", current_event.x, current_event.y);
                        if (current_event.x == 20) {
                            cst816x->is_volume_long_pressing_ = true;
                            cst816x->volume_long_press_dir_ = 1;
                            cst816x->last_volume_adjust_time_ = current_time;
                        } else if (current_event.x == 60) {
                            cst816x->is_volume_long_pressing_ = true;
                            cst816x->volume_long_press_dir_ = -1; 
                            cst816x->last_volume_adjust_time_ = current_time;
                        }
                        break;

                    case TouchEventType::LONG_PRESS_END:
                        ESP_LOGI(TAG, "Long press ended at (%d, %d) → Stop volume adjust", current_event.x, current_event.y);
                        if (current_event.x == 20 || current_event.x == 60) {
                            cst816x->is_volume_long_pressing_ = false;
                            cst816x->volume_long_press_dir_ = 0;
                            cst816x->last_volume_adjust_time_ = 0;
                        }
                        break;
                }
            }
        }

        if (cst816x->is_volume_long_pressing_) {
            int64_t now = cst816x->getCurrentTimeUs();
            if (now - cst816x->last_volume_adjust_time_ >= cst816x->VOL_ADJ_INTERVAL_US) {
                int current_vol = codec->output_volume();
                int new_vol = current_vol + (cst816x->volume_long_press_dir_ * cst816x->VOL_ADJ_STEP);
                
                new_vol = std::max(ES8311_VOL_MIN, std::min(ES8311_VOL_MAX, new_vol));
                
                if (new_vol != current_vol) {
                    codec->EnableOutput(true);
                    codec->SetOutputVolume(new_vol);
                    display->ShowNotification(Lang::Strings::VOLUME + std::to_string(new_vol));
                    cst816x->last_volume_adjust_time_ = now; 
                } else {
                    cst816x->is_volume_long_pressing_ = false;
                    cst816x->volume_long_press_dir_ = 0;
                    ESP_LOGI(TAG, "Volume reached limit (%d), stop adjusting", new_vol);
                }
            }
        }

        vTaskDelay(pdMS_TO_TICKS(40));
    }
}

void Cst816x::InitCst816d() {
    ESP_LOGI(TAG, "Init CST816x touch driver");
    xTaskCreate(touchpad_daemon, "touch_daemon", 2048, this, 1, NULL);
}