#include "PowerNodeWidget.hpp"
#include "../Fonts.hpp"
#include <cstring>
#include <cstdio>

PowerNodeWidget::PowerNodeWidget(const WidgetConfig& config)
    : Widget(config)
{
    labelText_[0] = '\0';
    valueFormat_[0] = '\0';
}

int PowerNodeWidget::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 PowerNodeWidget::parseText() {
    labelText_[0] = '\0';
    valueFormat_[0] = '\0';

    const char* text = config_.text;
    if (!text || text[0] == '\0') return;

    const char* newline = strchr(text, '\n');
    if (newline) {
        size_t labelLen = static_cast<size_t>(newline - text);
        if (labelLen >= MAX_TEXT_LEN) labelLen = MAX_TEXT_LEN - 1;
        memcpy(labelText_, text, labelLen);
        labelText_[labelLen] = '\0';
        strncpy(valueFormat_, newline + 1, MAX_TEXT_LEN - 1);
        valueFormat_[MAX_TEXT_LEN - 1] = '\0';
    } else {
        strncpy(labelText_, text, MAX_TEXT_LEN - 1);
        labelText_[MAX_TEXT_LEN - 1] = '\0';
    }
}

lv_obj_t* PowerNodeWidget::create(lv_obj_t* parent) {
    parseText();

    obj_ = lv_obj_create(parent);
    if (obj_ == nullptr) {
        return nullptr;
    }

    lv_obj_remove_style_all(obj_);
    lv_obj_set_pos(obj_, config_.x, config_.y);
    lv_obj_set_size(obj_,
        config_.width > 0 ? config_.width : 120,
        config_.height > 0 ? config_.height : 120);
    lv_obj_clear_flag(obj_, LV_OBJ_FLAG_SCROLLABLE);

    lv_obj_set_flex_flow(obj_, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_flex_align(obj_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
    lv_obj_set_style_pad_all(obj_, 6, 0);
    lv_obj_set_style_pad_gap(obj_, 2, 0);

    if (labelText_[0] != '\0') {
        labelLabel_ = lv_label_create(obj_);
        lv_label_set_text(labelLabel_, labelText_);
        lv_obj_clear_flag(labelLabel_, LV_OBJ_FLAG_CLICKABLE);
    }

    if (config_.iconCodepoint > 0 && Fonts::hasIconFont()) {
        iconLabel_ = lv_label_create(obj_);
        char iconText[5];
        encodeUtf8(config_.iconCodepoint, iconText);
        lv_label_set_text(iconLabel_, iconText);
        lv_obj_clear_flag(iconLabel_, LV_OBJ_FLAG_CLICKABLE);
    }

    valueLabel_ = lv_label_create(obj_);
    if (valueFormat_[0] != '\0') {
        lv_label_set_text(valueLabel_, valueFormat_);
    } else {
        lv_label_set_text(valueLabel_, "");
    }
    lv_obj_clear_flag(valueLabel_, LV_OBJ_FLAG_CLICKABLE);

    return obj_;
}

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

    lv_obj_set_style_bg_color(obj_, lv_color_white(), 0);
    lv_obj_set_style_bg_opa(obj_, LV_OPA_COVER, 0);
    lv_obj_set_style_radius(obj_, LV_RADIUS_CIRCLE, 0);

    int16_t minSide = config_.width < config_.height ? config_.width : config_.height;
    int16_t ring = minSide / 12;
    if (ring < 2) ring = 2;
    if (ring > 12) ring = 12;

    lv_obj_set_style_border_width(obj_, ring, 0);
    lv_obj_set_style_border_color(obj_, lv_color_make(
        config_.bgColor.r, config_.bgColor.g, config_.bgColor.b), 0);
    lv_obj_set_style_border_opa(obj_, config_.bgOpacity, 0);

    applyShadowStyle();

    uint8_t valueSizeIdx = config_.fontSize;
    uint8_t labelSizeIdx = valueSizeIdx > 0 ? static_cast<uint8_t>(valueSizeIdx - 1) : valueSizeIdx;

    if (labelLabel_ != nullptr) {
        lv_obj_set_style_text_color(labelLabel_, lv_color_make(
            config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
        lv_obj_set_style_text_font(labelLabel_, Fonts::bySizeIndex(labelSizeIdx), 0);
        lv_obj_set_style_text_align(labelLabel_, LV_TEXT_ALIGN_CENTER, 0);
        lv_obj_set_style_text_opa(labelLabel_, LV_OPA_70, 0);
    }

    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 : valueSizeIdx;
        lv_obj_set_style_text_font(iconLabel_, Fonts::iconFont(sizeIdx), 0);
        lv_obj_set_style_text_align(iconLabel_, LV_TEXT_ALIGN_CENTER, 0);
    }

    if (valueLabel_ != nullptr) {
        lv_obj_set_style_text_color(valueLabel_, lv_color_make(
            config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
        lv_obj_set_style_text_font(valueLabel_, Fonts::bySizeIndex(valueSizeIdx), 0);
        lv_obj_set_style_text_align(valueLabel_, LV_TEXT_ALIGN_CENTER, 0);
    }
}

void PowerNodeWidget::updateValueText(const char* text) {
    if (valueLabel_ == nullptr || text == nullptr) return;
    lv_label_set_text(valueLabel_, text);
}

void PowerNodeWidget::onKnxValue(float value) {
    if (valueLabel_ == nullptr) return;
    if (config_.textSource != TextSource::KNX_DPT_TEMP &&
        config_.textSource != TextSource::KNX_DPT_PERCENT) return;

    char buf[32];
    const char* fmt = valueFormat_[0] != '\0' ? valueFormat_ : "%0.1f";

    if (config_.textSource == TextSource::KNX_DPT_PERCENT) {
        int percent = static_cast<int>(value + 0.5f);
        snprintf(buf, sizeof(buf), fmt, percent);
    } else {
        snprintf(buf, sizeof(buf), fmt, value);
    }

    updateValueText(buf);
}

void PowerNodeWidget::onKnxSwitch(bool value) {
    if (valueLabel_ == nullptr) return;
    if (config_.textSource != TextSource::KNX_DPT_SWITCH) return;
    updateValueText(value ? "EIN" : "AUS");
}

void PowerNodeWidget::onKnxText(const char* text) {
    if (valueLabel_ == nullptr) return;
    if (config_.textSource != TextSource::KNX_DPT_TEXT) return;
    updateValueText(text);
}
