#include "Widget.hpp"
#include "../Fonts.hpp"
#include "../WidgetManager.hpp"
#include "lvgl.h"

Widget::Widget(const WidgetConfig& config)
    : config_(config)
    , obj_(nullptr)
{
}

Widget::~Widget() {
    destroy();
}

void Widget::destroy() {
    if (obj_ != nullptr) {
        if (lv_obj_is_valid(obj_)) {
            lv_obj_delete(obj_);
        }
        obj_ = nullptr;
    }
}

void Widget::applyStyle() {
    if (obj_ == nullptr) return;
    applyCommonStyle();
}

void Widget::onKnxValue(float value) {
    cachedPrimaryValue_ = value;
    hasCachedPrimary_ = true;
    evaluateConditions(cachedPrimaryValue_, cachedSecondaryValue_, cachedTertiaryValue_);
}

void Widget::onKnxValue2(float value) {
    cachedSecondaryValue_ = value;
    hasCachedSecondary_ = true;
    evaluateConditions(cachedPrimaryValue_, cachedSecondaryValue_, cachedTertiaryValue_);
}

void Widget::onKnxValue3(float value) {
    cachedTertiaryValue_ = value;
    hasCachedTertiary_ = true;
    evaluateConditions(cachedPrimaryValue_, cachedSecondaryValue_, cachedTertiaryValue_);
}

void Widget::onKnxSwitch(bool /*value*/) {
    // Default: do nothing
}

void Widget::onKnxText(const char* /*text*/) {
    // Default: do nothing
}

void Widget::onKnxTime(const struct tm& /*value*/, TextSource /*source*/) {
    // Default: do nothing
}

void Widget::onHistoryUpdate() {
    // Default: do nothing
}

bool Widget::evaluateConditions(float primaryValue, float secondaryValue, float tertiaryValue) {
    if (config_.conditionCount == 0) return false;

    const StyleCondition* bestMatch = nullptr;
    uint8_t bestPriority = 255;

    for (uint8_t i = 0; i < config_.conditionCount && i < MAX_CONDITIONS; ++i) {
        const StyleCondition& cond = config_.conditions[i];
        if (!cond.enabled) continue;

        // Get the value to check based on source
        float checkValue = 0.0f;
        bool hasValue = false;
        switch (cond.source) {
            case ConditionSource::PRIMARY:
                checkValue = primaryValue;
                hasValue = hasCachedPrimary_;
                break;
            case ConditionSource::SECONDARY:
                checkValue = secondaryValue;
                hasValue = hasCachedSecondary_;
                break;
            case ConditionSource::TERTIARY:
                checkValue = tertiaryValue;
                hasValue = hasCachedTertiary_;
                break;
        }

        if (!hasValue) continue;

        // Evaluate condition
        bool matches = false;
        switch (cond.op) {
            case ConditionOp::LESS:
                matches = checkValue < cond.threshold;
                break;
            case ConditionOp::LESS_EQUAL:
                matches = checkValue <= cond.threshold;
                break;
            case ConditionOp::EQUAL:
                matches = checkValue == cond.threshold;
                break;
            case ConditionOp::GREATER_EQUAL:
                matches = checkValue >= cond.threshold;
                break;
            case ConditionOp::GREATER:
                matches = checkValue > cond.threshold;
                break;
            case ConditionOp::NOT_EQUAL:
                matches = checkValue != cond.threshold;
                break;
        }

        if (matches && cond.priority < bestPriority) {
            bestMatch = &cond;
            bestPriority = cond.priority;
        }
    }

    if (bestMatch) {
        applyConditionStyle(bestMatch->style);
        return true;
    }

    return false;
}

void Widget::applyConditionStyle(const ConditionStyle& style) {
    if (obj_ == nullptr) return;

    // Handle hide flag
    if (style.flags & ConditionStyle::FLAG_HIDE) {
        lv_obj_add_flag(obj_, LV_OBJ_FLAG_HIDDEN);
        return;
    } else {
        lv_obj_clear_flag(obj_, LV_OBJ_FLAG_HIDDEN);
    }

    // Apply text color if flag set
    if (style.flags & ConditionStyle::FLAG_USE_TEXT_COLOR) {
        lv_obj_set_style_text_color(obj_, lv_color_make(
            style.textColor.r, style.textColor.g, style.textColor.b), 0);
    }

    // Apply background color if flag set
    if (style.flags & ConditionStyle::FLAG_USE_BG_COLOR) {
        lv_obj_set_style_bg_color(obj_, lv_color_make(
            style.bgColor.r, style.bgColor.g, style.bgColor.b), 0);
    }

    // Apply background opacity if flag set
    if (style.flags & ConditionStyle::FLAG_USE_BG_OPACITY) {
        lv_obj_set_style_bg_opa(obj_, style.bgOpacity, 0);
    }

    // Icon changes are handled by subclasses that have icons
    if (style.iconCodepoint != 0) {
        currentConditionIcon_ = style.iconCodepoint;
    }
}

bool Widget::shouldTransformColors() const {
    return WidgetManager::instance().isNightMode() && !config_.themeFixed;
}

Color Widget::themeColor(const Color& c) const {
    return shouldTransformColors() ? c.invertLightness() : c;
}

void Widget::applyCommonStyle() {
    if (obj_ == nullptr) return;

    Color textCol = themeColor(config_.textColor);
    Color bgCol = themeColor(config_.bgColor);
    Color borderCol = themeColor(config_.borderColor);

    // Text color
    lv_obj_set_style_text_color(obj_, lv_color_make(textCol.r, textCol.g, textCol.b), 0);

    // Font
    lv_obj_set_style_text_font(obj_, getFontBySize(config_.fontSize), 0);

    // Background (for buttons and labels with bg)
    if (config_.bgOpacity > 0) {
        lv_obj_set_style_bg_color(obj_, lv_color_make(bgCol.r, bgCol.g, bgCol.b), 0);
        lv_obj_set_style_bg_opa(obj_, config_.bgOpacity, 0);
    }

    // Border radius
    if (config_.borderRadius > 0) {
        lv_obj_set_style_radius(obj_, config_.borderRadius, 0);
    }

    // Border
    if (config_.borderWidth > 0 && config_.borderOpacity > 0) {
        lv_obj_set_style_border_width(obj_, config_.borderWidth, 0);
        lv_obj_set_style_border_color(obj_, lv_color_make(borderCol.r, borderCol.g, borderCol.b), 0);
        lv_obj_set_style_border_opa(obj_, config_.borderOpacity, 0);
    } else {
        lv_obj_set_style_border_width(obj_, 0, 0);
    }

    // Shadow
    applyShadowStyle();
}

void Widget::applyShadowStyle() {
    if (obj_ == nullptr || !config_.shadow.enabled || config_.type == WidgetType::BUTTON) return;

    // Limit shadow values to prevent memory issues on ESP32
    constexpr int16_t MAX_SHADOW_BLUR = 15;
    constexpr int16_t MAX_SHADOW_SPREAD = 8;

    int16_t blur = config_.shadow.blur;
    int16_t spread = config_.shadow.spread;

    if (blur > MAX_SHADOW_BLUR) blur = MAX_SHADOW_BLUR;
    if (blur < 0) blur = 0;
    if (spread > MAX_SHADOW_SPREAD) spread = MAX_SHADOW_SPREAD;
    if (spread < 0) spread = 0;
    if (blur == 0) return;

    Color sc = themeColor(config_.shadow.color);
    lv_color_t shadowColor = lv_color_make(sc.r, sc.g, sc.b);

    // Default state shadow
    lv_obj_set_style_shadow_color(obj_, shadowColor, 0);
    lv_obj_set_style_shadow_opa(obj_, 180, 0);
    lv_obj_set_style_shadow_width(obj_, blur, 0);
    lv_obj_set_style_shadow_spread(obj_, spread, 0);
    lv_obj_set_style_shadow_offset_x(obj_, config_.shadow.offsetX, 0);
    lv_obj_set_style_shadow_offset_y(obj_, config_.shadow.offsetY, 0);

}

const lv_font_t* Widget::getFontBySize(uint8_t sizeIndex) {
    return Fonts::bySizeIndex(sizeIndex);
}
