#include "ButtonWidget.hpp"
#include "../WidgetManager.hpp"
#include "../Fonts.hpp"
#include "esp_log.h"

static const char* TAG = "ButtonWidget";

ButtonWidget::ButtonWidget(const WidgetConfig& config)
    : Widget(config)
    , contentContainer_(nullptr)
    , label_(nullptr)
    , iconLabel_(nullptr)
{
}

ButtonWidget::~ButtonWidget() {
    // Remove event callback BEFORE the base class destructor deletes the object
    if (obj_) {
        lv_obj_remove_event_cb(obj_, clickCallback);
    }
    contentContainer_ = nullptr;
    label_ = nullptr;
    iconLabel_ = nullptr;
}

int ButtonWidget::encodeUtf8(uint32_t codepoint, char* buf) {
    if (codepoint < 0x80) {
        buf[0] = static_cast<char>(codepoint);
        buf[1] = '\0';
        return 1;
    } else if (codepoint < 0x800) {
        buf[0] = static_cast<char>(0xC0 | (codepoint >> 6));
        buf[1] = static_cast<char>(0x80 | (codepoint & 0x3F));
        buf[2] = '\0';
        return 2;
    } else if (codepoint < 0x10000) {
        buf[0] = static_cast<char>(0xE0 | (codepoint >> 12));
        buf[1] = static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F));
        buf[2] = static_cast<char>(0x80 | (codepoint & 0x3F));
        buf[3] = '\0';
        return 3;
    } else if (codepoint < 0x110000) {
        buf[0] = static_cast<char>(0xF0 | (codepoint >> 18));
        buf[1] = static_cast<char>(0x80 | ((codepoint >> 12) & 0x3F));
        buf[2] = static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F));
        buf[3] = static_cast<char>(0x80 | (codepoint & 0x3F));
        buf[4] = '\0';
        return 4;
    }
    buf[0] = '\0';
    return 0;
}

void ButtonWidget::clickCallback(lv_event_t* e) {
    printf("ButtonWidget::clickCallback\n"); 
    fflush(stdout);
    ButtonWidget* widget = static_cast<ButtonWidget*>(lv_event_get_user_data(e));
    if (!widget) {
        printf("ButtonWidget: Widget is null!\n");
        fflush(stdout);
        return;
    }
    lv_obj_t* target = static_cast<lv_obj_t*>(lv_event_get_target(e));
    WidgetManager::instance().handleButtonAction(widget->getConfig(), target);
}

void ButtonWidget::setupFlexLayout() {
    if (contentContainer_ == nullptr) return;

    // Determine flex direction based on icon position
    bool isVertical = (config_.iconPosition == static_cast<uint8_t>(IconPosition::TOP) ||
                       config_.iconPosition == static_cast<uint8_t>(IconPosition::BOTTOM));

    lv_obj_set_flex_flow(contentContainer_,
        isVertical ? LV_FLEX_FLOW_COLUMN : LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(contentContainer_,
        LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);

    // Set gap between icon and text
    int gap = config_.iconGap > 0 ? config_.iconGap : 8;
    lv_obj_set_style_pad_gap(contentContainer_, gap, 0);
}

lv_obj_t* ButtonWidget::create(lv_obj_t* parent) {
    obj_ = lv_btn_create(parent);
    lv_obj_set_pos(obj_, config_.x, config_.y);
    lv_obj_set_size(obj_, config_.width > 0 ? config_.width : 100,
                          config_.height > 0 ? config_.height : 50);

    lv_obj_add_event_cb(obj_, clickCallback, LV_EVENT_CLICKED, this);

    bool hasIcon = config_.iconCodepoint > 0 && Fonts::hasIconFont();

    if (hasIcon) {
        // Create container for flex layout
        contentContainer_ = lv_obj_create(obj_);
        lv_obj_remove_style_all(contentContainer_);
        lv_obj_set_size(contentContainer_, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
        lv_obj_center(contentContainer_);
        lv_obj_clear_flag(contentContainer_, LV_OBJ_FLAG_CLICKABLE); // Pass clicks to parent

        // Create icon label
        bool iconFirst = (config_.iconPosition == static_cast<uint8_t>(IconPosition::LEFT) ||
                          config_.iconPosition == static_cast<uint8_t>(IconPosition::TOP));

        if (iconFirst) {
            iconLabel_ = lv_label_create(contentContainer_);
            char iconText[5];
            encodeUtf8(config_.iconCodepoint, iconText);
            lv_label_set_text(iconLabel_, iconText);
            lv_obj_clear_flag(iconLabel_, LV_OBJ_FLAG_CLICKABLE);
        }

        // Create text label
        label_ = lv_label_create(contentContainer_);
        lv_label_set_text(label_, config_.text);
        lv_obj_clear_flag(label_, LV_OBJ_FLAG_CLICKABLE);

        if (!iconFirst) {
            iconLabel_ = lv_label_create(contentContainer_);
            char iconText[5];
            encodeUtf8(config_.iconCodepoint, iconText);
            lv_label_set_text(iconLabel_, iconText);
            lv_obj_clear_flag(iconLabel_, LV_OBJ_FLAG_CLICKABLE);
        }

        setupFlexLayout();
    } else {
        // Simple button without icon
        label_ = lv_label_create(obj_);
        lv_label_set_text(label_, config_.text);
        lv_obj_center(label_);
        lv_obj_clear_flag(label_, LV_OBJ_FLAG_CLICKABLE);
    }

    ESP_LOGI(TAG, "Created button '%s' at %d,%d (icon: 0x%lx)",
             config_.text, config_.x, config_.y, (unsigned long)config_.iconCodepoint);
    return obj_;
}

void ButtonWidget::applyStyle() {
    if (obj_ == nullptr) return;

    // Apply common style to button
    applyCommonStyle();

    // Apply text style to label
    if (label_ != nullptr) {
        lv_obj_set_style_text_color(label_, lv_color_make(
            config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
        lv_obj_set_style_text_font(label_, getFontBySize(config_.fontSize), 0);
    }

    // Apply icon style
    if (iconLabel_ != nullptr) {
        lv_obj_set_style_text_color(iconLabel_, lv_color_make(
            config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);

        uint8_t sizeIdx = config_.iconSize < 6 ? config_.iconSize : config_.fontSize;
        lv_obj_set_style_text_font(iconLabel_, Fonts::iconFont(sizeIdx), 0);
    }
}

bool ButtonWidget::isChecked() const {
    if (obj_ == nullptr) return false;
    return (lv_obj_get_state(obj_) & LV_STATE_CHECKED) != 0;
}
