#include "WidgetConfig.hpp"
#include <cstring>
#include <cstdio>

// WidgetConfig implementation
void WidgetConfig::serialize(uint8_t* buf) const {
    memset(buf, 0, SERIALIZED_SIZE);
    size_t pos = 0;

    buf[pos++] = id;
    buf[pos++] = static_cast<uint8_t>(type);
    buf[pos++] = x & 0xFF; buf[pos++] = (x >> 8) & 0xFF;
    buf[pos++] = y & 0xFF; buf[pos++] = (y >> 8) & 0xFF;
    buf[pos++] = width & 0xFF; buf[pos++] = (width >> 8) & 0xFF;
    buf[pos++] = height & 0xFF; buf[pos++] = (height >> 8) & 0xFF;
    buf[pos++] = visible ? 1 : 0;

    buf[pos++] = static_cast<uint8_t>(textSource);
    memcpy(&buf[pos], text, MAX_TEXT_LEN); pos += MAX_TEXT_LEN;
    buf[pos++] = knxAddress & 0xFF; buf[pos++] = (knxAddress >> 8) & 0xFF;
    buf[pos++] = fontSize;
    buf[pos++] = textAlign;
    buf[pos++] = isContainer ? 1 : 0;

    buf[pos++] = textColor.r; buf[pos++] = textColor.g; buf[pos++] = textColor.b;
    buf[pos++] = bgColor.r; buf[pos++] = bgColor.g; buf[pos++] = bgColor.b;
    buf[pos++] = bgOpacity;
    buf[pos++] = borderRadius;
    buf[pos++] = borderWidth;
    buf[pos++] = borderColor.r; buf[pos++] = borderColor.g; buf[pos++] = borderColor.b;
    buf[pos++] = borderOpacity;

    buf[pos++] = shadow.offsetX;
    buf[pos++] = shadow.offsetY;
    buf[pos++] = shadow.blur;
    buf[pos++] = shadow.spread;
    buf[pos++] = shadow.color.r; buf[pos++] = shadow.color.g; buf[pos++] = shadow.color.b;
    buf[pos++] = shadow.enabled ? 1 : 0;

    buf[pos++] = isToggle ? 1 : 0;
    buf[pos++] = knxAddressWrite & 0xFF; buf[pos++] = (knxAddressWrite >> 8) & 0xFF;
    buf[pos++] = static_cast<uint8_t>(action);
    buf[pos++] = targetScreen;

    // Icon properties
    buf[pos++] = iconCodepoint & 0xFF;
    buf[pos++] = (iconCodepoint >> 8) & 0xFF;
    buf[pos++] = (iconCodepoint >> 16) & 0xFF;
    buf[pos++] = (iconCodepoint >> 24) & 0xFF;
    buf[pos++] = iconPosition;
    buf[pos++] = iconSize;
    buf[pos++] = static_cast<uint8_t>(iconGap);
    buf[pos++] = iconPositionX & 0xFF;
    buf[pos++] = (iconPositionX >> 8) & 0xFF;
    buf[pos++] = iconPositionY & 0xFF;
    buf[pos++] = (iconPositionY >> 8) & 0xFF;

    // Hierarchy
    buf[pos++] = static_cast<uint8_t>(parentId);

    // Chart properties
    buf[pos++] = chartPeriod;
    buf[pos++] = chartSeriesCount;
    for (size_t i = 0; i < CHART_MAX_SERIES; ++i) {
        buf[pos++] = chartKnxAddress[i] & 0xFF;
        buf[pos++] = (chartKnxAddress[i] >> 8) & 0xFF;
    }
    for (size_t i = 0; i < CHART_MAX_SERIES; ++i) {
        buf[pos++] = static_cast<uint8_t>(chartTextSource[i]);
    }
    for (size_t i = 0; i < CHART_MAX_SERIES; ++i) {
        buf[pos++] = chartSeriesColor[i].r;
        buf[pos++] = chartSeriesColor[i].g;
        buf[pos++] = chartSeriesColor[i].b;
    }

    // Secondary KNX address (left value)
    buf[pos++] = knxAddress2 & 0xFF;
    buf[pos++] = (knxAddress2 >> 8) & 0xFF;
    buf[pos++] = static_cast<uint8_t>(textSource2);
    memcpy(&buf[pos], text2, MAX_FORMAT_LEN); pos += MAX_FORMAT_LEN;

    // Tertiary KNX address (right value)
    buf[pos++] = knxAddress3 & 0xFF;
    buf[pos++] = (knxAddress3 >> 8) & 0xFF;
    buf[pos++] = static_cast<uint8_t>(textSource3);
    memcpy(&buf[pos], text3, MAX_FORMAT_LEN); pos += MAX_FORMAT_LEN;

    // Conditions
    buf[pos++] = conditionCount;
    for (size_t i = 0; i < MAX_CONDITIONS; ++i) {
        const StyleCondition& cond = conditions[i];
        // threshold (4 bytes as float)
        memcpy(&buf[pos], &cond.threshold, sizeof(float)); pos += sizeof(float);
        buf[pos++] = static_cast<uint8_t>(cond.op);
        buf[pos++] = static_cast<uint8_t>(cond.source);
        buf[pos++] = cond.priority;
        // ConditionStyle
        buf[pos++] = cond.style.iconCodepoint & 0xFF;
        buf[pos++] = (cond.style.iconCodepoint >> 8) & 0xFF;
        buf[pos++] = (cond.style.iconCodepoint >> 16) & 0xFF;
        buf[pos++] = (cond.style.iconCodepoint >> 24) & 0xFF;
        buf[pos++] = cond.style.textColor.r;
        buf[pos++] = cond.style.textColor.g;
        buf[pos++] = cond.style.textColor.b;
        buf[pos++] = cond.style.bgColor.r;
        buf[pos++] = cond.style.bgColor.g;
        buf[pos++] = cond.style.bgColor.b;
        buf[pos++] = cond.style.bgOpacity;
        buf[pos++] = cond.style.flags;
        buf[pos++] = cond.enabled ? 1 : 0;
    }

    // RoomCard sub-buttons
    buf[pos++] = subButtonCount;
    buf[pos++] = subButtonSize;
    buf[pos++] = subButtonDistance;
    buf[pos++] = subButtonOpacity;
    buf[pos++] = cardStyle;
    for (size_t i = 0; i < MAX_SUBBUTTONS; ++i) {
        const SubButtonConfig& sb = subButtons[i];
        buf[pos++] = sb.iconCodepointOff & 0xFF;
        buf[pos++] = (sb.iconCodepointOff >> 8) & 0xFF;
        buf[pos++] = (sb.iconCodepointOff >> 16) & 0xFF;
        buf[pos++] = (sb.iconCodepointOff >> 24) & 0xFF;
        buf[pos++] = sb.iconCodepointOn & 0xFF;
        buf[pos++] = (sb.iconCodepointOn >> 8) & 0xFF;
        buf[pos++] = (sb.iconCodepointOn >> 16) & 0xFF;
        buf[pos++] = (sb.iconCodepointOn >> 24) & 0xFF;
        buf[pos++] = sb.knxAddrRead & 0xFF;
        buf[pos++] = (sb.knxAddrRead >> 8) & 0xFF;
        buf[pos++] = sb.knxAddrWrite & 0xFF;
        buf[pos++] = (sb.knxAddrWrite >> 8) & 0xFF;
        buf[pos++] = sb.bgColorOn.r;
        buf[pos++] = sb.bgColorOn.g;
        buf[pos++] = sb.bgColorOn.b;
        buf[pos++] = sb.bgColorOff.r;
        buf[pos++] = sb.bgColorOff.g;
        buf[pos++] = sb.bgColorOff.b;
        buf[pos++] = sb.iconColorOn.r;
        buf[pos++] = sb.iconColorOn.g;
        buf[pos++] = sb.iconColorOn.b;
        buf[pos++] = sb.iconColorOff.r;
        buf[pos++] = sb.iconColorOff.g;
        buf[pos++] = sb.iconColorOff.b;
        buf[pos++] = static_cast<uint8_t>(sb.position);
        buf[pos++] = static_cast<uint8_t>(sb.action);
        buf[pos++] = sb.targetScreen;
        buf[pos++] = sb.enabled ? 1 : 0;
        buf[pos++] = 0; // padding
        buf[pos++] = 0; // padding
    }

    // Arc properties
    buf[pos++] = arcMin & 0xFF; buf[pos++] = (arcMin >> 8) & 0xFF;
    buf[pos++] = arcMax & 0xFF; buf[pos++] = (arcMax >> 8) & 0xFF;
    buf[pos++] = arcUnit;
    buf[pos++] = arcShowValue ? 1 : 0;
    buf[pos++] = static_cast<uint8_t>(arcScaleOffset);
    buf[pos++] = arcScaleColor.r;
    buf[pos++] = arcScaleColor.g;
    buf[pos++] = arcScaleColor.b;
    buf[pos++] = arcValueColor.r;
    buf[pos++] = arcValueColor.g;
    buf[pos++] = arcValueColor.b;
    buf[pos++] = arcValueFontSize;

    // Theme
    buf[pos++] = themeFixed ? 1 : 0;
}

void WidgetConfig::deserialize(const uint8_t* buf) {
    size_t pos = 0;

    id = buf[pos++];
    type = static_cast<WidgetType>(buf[pos++]);
    x = buf[pos] | (buf[pos+1] << 8); pos += 2;
    y = buf[pos] | (buf[pos+1] << 8); pos += 2;
    width = buf[pos] | (buf[pos+1] << 8); pos += 2;
    height = buf[pos] | (buf[pos+1] << 8); pos += 2;
    visible = buf[pos++] != 0;

    textSource = static_cast<TextSource>(buf[pos++]);
    memcpy(text, &buf[pos], MAX_TEXT_LEN); pos += MAX_TEXT_LEN;
    text[MAX_TEXT_LEN - 1] = '\0';
    knxAddress = buf[pos] | (buf[pos+1] << 8); pos += 2;
    fontSize = buf[pos++];
    textAlign = buf[pos++];
    isContainer = buf[pos++] != 0;

    textColor.r = buf[pos++]; textColor.g = buf[pos++]; textColor.b = buf[pos++];
    bgColor.r = buf[pos++]; bgColor.g = buf[pos++]; bgColor.b = buf[pos++];
    bgOpacity = buf[pos++];
    borderRadius = buf[pos++];
    borderWidth = buf[pos++];
    borderColor.r = buf[pos++]; borderColor.g = buf[pos++]; borderColor.b = buf[pos++];
    borderOpacity = buf[pos++];

    shadow.offsetX = static_cast<int8_t>(buf[pos++]);
    shadow.offsetY = static_cast<int8_t>(buf[pos++]);
    shadow.blur = buf[pos++];
    shadow.spread = buf[pos++];
    shadow.color.r = buf[pos++]; shadow.color.g = buf[pos++]; shadow.color.b = buf[pos++];
    shadow.enabled = buf[pos++] != 0;

    isToggle = buf[pos++] != 0;
    knxAddressWrite = buf[pos] | (buf[pos+1] << 8);
    pos += 2;
    action = static_cast<ButtonAction>(buf[pos++]);
    targetScreen = buf[pos++];

    // Icon properties
    iconCodepoint = buf[pos] | (buf[pos+1] << 8) | (buf[pos+2] << 16) | (buf[pos+3] << 24);
    pos += 4;
    iconPosition = buf[pos++];
    iconSize = buf[pos++];
    iconGap = static_cast<int8_t>(buf[pos++]);
    iconPositionX = static_cast<int16_t>(buf[pos] | (buf[pos+1] << 8));
    pos += 2;
    iconPositionY = static_cast<int16_t>(buf[pos] | (buf[pos+1] << 8));
    pos += 2;

    // Hierarchy
    parentId = static_cast<int8_t>(buf[pos++]);

    // Chart properties
    chartPeriod = buf[pos++];
    chartSeriesCount = buf[pos++];
    for (size_t i = 0; i < CHART_MAX_SERIES; ++i) {
        chartKnxAddress[i] = buf[pos] | (buf[pos + 1] << 8);
        pos += 2;
    }
    for (size_t i = 0; i < CHART_MAX_SERIES; ++i) {
        chartTextSource[i] = static_cast<TextSource>(buf[pos++]);
    }
    for (size_t i = 0; i < CHART_MAX_SERIES; ++i) {
        chartSeriesColor[i].r = buf[pos++];
        chartSeriesColor[i].g = buf[pos++];
        chartSeriesColor[i].b = buf[pos++];
    }

    // Secondary KNX address (left value) - check bounds for backward compatibility
    if (pos + 19 <= SERIALIZED_SIZE) {
        knxAddress2 = buf[pos] | (buf[pos + 1] << 8); pos += 2;
        textSource2 = static_cast<TextSource>(buf[pos++]);
        memcpy(text2, &buf[pos], MAX_FORMAT_LEN); pos += MAX_FORMAT_LEN;
        text2[MAX_FORMAT_LEN - 1] = '\0';
    } else {
        knxAddress2 = 0;
        textSource2 = TextSource::STATIC;
        text2[0] = '\0';
    }

    // Tertiary KNX address (right value)
    if (pos + 19 <= SERIALIZED_SIZE) {
        knxAddress3 = buf[pos] | (buf[pos + 1] << 8); pos += 2;
        textSource3 = static_cast<TextSource>(buf[pos++]);
        memcpy(text3, &buf[pos], MAX_FORMAT_LEN); pos += MAX_FORMAT_LEN;
        text3[MAX_FORMAT_LEN - 1] = '\0';
    } else {
        knxAddress3 = 0;
        textSource3 = TextSource::STATIC;
        text3[0] = '\0';
    }

    // Conditions
    if (pos + 1 <= SERIALIZED_SIZE) {
        conditionCount = buf[pos++];
        if (conditionCount > MAX_CONDITIONS) conditionCount = MAX_CONDITIONS;
    } else {
        conditionCount = 0;
    }

    for (size_t i = 0; i < MAX_CONDITIONS; ++i) {
        StyleCondition& cond = conditions[i];
        if (pos + 20 <= SERIALIZED_SIZE) {
            memcpy(&cond.threshold, &buf[pos], sizeof(float)); pos += sizeof(float);
            cond.op = static_cast<ConditionOp>(buf[pos++]);
            cond.source = static_cast<ConditionSource>(buf[pos++]);
            cond.priority = buf[pos++];
            cond.style.iconCodepoint = buf[pos] | (buf[pos + 1] << 8) |
                                       (buf[pos + 2] << 16) | (buf[pos + 3] << 24);
            pos += 4;
            cond.style.textColor.r = buf[pos++];
            cond.style.textColor.g = buf[pos++];
            cond.style.textColor.b = buf[pos++];
            cond.style.bgColor.r = buf[pos++];
            cond.style.bgColor.g = buf[pos++];
            cond.style.bgColor.b = buf[pos++];
            cond.style.bgOpacity = buf[pos++];
            cond.style.flags = buf[pos++];
            cond.enabled = buf[pos++] != 0;
        } else {
            cond = StyleCondition{};
        }
    }

    // RoomCard sub-buttons
    if (pos + 5 <= SERIALIZED_SIZE) {
        subButtonCount = buf[pos++];
        if (subButtonCount > MAX_SUBBUTTONS) subButtonCount = MAX_SUBBUTTONS;
        subButtonSize = buf[pos++];
        if (subButtonSize == 0) subButtonSize = 40; // Default
        subButtonDistance = buf[pos++];
        if (subButtonDistance == 0) subButtonDistance = 80; // Default 80px
        subButtonOpacity = buf[pos++];
        if (subButtonOpacity == 0) subButtonOpacity = 255; // Default fully opaque
        cardStyle = buf[pos++];  // 0=Bubble, 1=Tile
    } else {
        subButtonCount = 0;
        subButtonSize = 40;
        subButtonDistance = 80;
        subButtonOpacity = 255;
        cardStyle = 0;  // Default to Bubble style
    }

    for (size_t i = 0; i < MAX_SUBBUTTONS; ++i) {
        SubButtonConfig& sb = subButtons[i];
        if (pos + 30 <= SERIALIZED_SIZE) {
            sb.iconCodepointOff = buf[pos] | (buf[pos + 1] << 8) |
                                  (buf[pos + 2] << 16) | (buf[pos + 3] << 24);
            pos += 4;
            sb.iconCodepointOn = buf[pos] | (buf[pos + 1] << 8) |
                                 (buf[pos + 2] << 16) | (buf[pos + 3] << 24);
            pos += 4;
            sb.knxAddrRead = buf[pos] | (buf[pos + 1] << 8); pos += 2;
            sb.knxAddrWrite = buf[pos] | (buf[pos + 1] << 8); pos += 2;
            sb.bgColorOn.r = buf[pos++];
            sb.bgColorOn.g = buf[pos++];
            sb.bgColorOn.b = buf[pos++];
            sb.bgColorOff.r = buf[pos++];
            sb.bgColorOff.g = buf[pos++];
            sb.bgColorOff.b = buf[pos++];
            sb.iconColorOn.r = buf[pos++];
            sb.iconColorOn.g = buf[pos++];
            sb.iconColorOn.b = buf[pos++];
            sb.iconColorOff.r = buf[pos++];
            sb.iconColorOff.g = buf[pos++];
            sb.iconColorOff.b = buf[pos++];
            sb.position = static_cast<SubButtonPosition>(buf[pos++]);
            sb.action = static_cast<SubButtonAction>(buf[pos++]);
            sb.targetScreen = buf[pos++];
            sb.enabled = buf[pos++] != 0;
            pos += 2; // padding
        } else {
            sb = SubButtonConfig{};
        }
    }

    // Arc properties
    if (pos + 6 <= SERIALIZED_SIZE) {
        arcMin = static_cast<int16_t>(buf[pos] | (buf[pos + 1] << 8)); pos += 2;
        arcMax = static_cast<int16_t>(buf[pos] | (buf[pos + 1] << 8)); pos += 2;
        arcUnit = buf[pos++];
        arcShowValue = buf[pos++] != 0;
    } else {
        arcMin = 0;
        arcMax = 100;
        arcUnit = 0;
        arcShowValue = true;
    }

    if (pos + 4 <= SERIALIZED_SIZE) {
        arcScaleOffset = static_cast<int8_t>(buf[pos++]);
        arcScaleColor.r = buf[pos++];
        arcScaleColor.g = buf[pos++];
        arcScaleColor.b = buf[pos++];
    } else {
        arcScaleOffset = 0;
        arcScaleColor = textColor;
    }

    if (pos + 4 <= SERIALIZED_SIZE) {
        arcValueColor.r = buf[pos++];
        arcValueColor.g = buf[pos++];
        arcValueColor.b = buf[pos++];
        arcValueFontSize = buf[pos++];
    } else {
        arcValueColor = textColor;
        arcValueFontSize = fontSize;
    }

    // Theme
    if (pos + 1 <= SERIALIZED_SIZE) {
        themeFixed = buf[pos++] != 0;
    } else {
        themeFixed = false;
    }
}

WidgetConfig WidgetConfig::createLabel(uint8_t id, int16_t x, int16_t y, const char* labelText) {
    WidgetConfig cfg = {};
    cfg.id = id;
    cfg.parentId = -1; // Root
    cfg.type = WidgetType::LABEL;
    cfg.x = x;
    cfg.y = y;
    cfg.width = 150;
    cfg.height = 40;
    cfg.visible = true;
    cfg.textSource = TextSource::STATIC;
    strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1);
    cfg.fontSize = 1; // 18pt
    cfg.textAlign = static_cast<uint8_t>(TextAlign::LEFT);
    cfg.isContainer = false;
    cfg.textColor = {255, 255, 255};
    cfg.bgColor = {0, 0, 0};
    cfg.bgOpacity = 0;
    cfg.borderRadius = 0;
    cfg.borderWidth = 0;
    cfg.borderColor = {255, 255, 255};
    cfg.borderOpacity = 0;
    cfg.arcMin = 0;
    cfg.arcMax = 100;
    cfg.arcUnit = 0;
    cfg.arcShowValue = true;
    cfg.arcScaleOffset = 0;
    cfg.arcScaleColor = cfg.textColor;
    cfg.arcValueColor = cfg.textColor;
    cfg.arcValueFontSize = cfg.fontSize;
    cfg.themeFixed = false;
    cfg.shadow.enabled = false;
    // Icon defaults
    cfg.iconCodepoint = 0;
    cfg.iconPosition = 0;
    cfg.iconSize = 1;
    cfg.iconGap = 8;
    // Secondary/tertiary address defaults
    cfg.knxAddress2 = 0;
    cfg.textSource2 = TextSource::STATIC;
    cfg.text2[0] = '\0';
    cfg.knxAddress3 = 0;
    cfg.textSource3 = TextSource::STATIC;
    cfg.text3[0] = '\0';
    // Conditions
    cfg.conditionCount = 0;
    // Sub-buttons
    cfg.subButtonCount = 0;
    cfg.subButtonSize = 40;
    cfg.subButtonDistance = 80;
    return cfg;
}

WidgetConfig WidgetConfig::createKnxLabel(uint8_t id, int16_t x, int16_t y,
                                           TextSource source, uint16_t knxAddr, const char* format) {
    WidgetConfig cfg = createLabel(id, x, y, format);
    cfg.textSource = source;
    cfg.knxAddress = knxAddr;
    return cfg;
}

WidgetConfig WidgetConfig::createButton(uint8_t id, int16_t x, int16_t y,
                                        const char* labelText, uint16_t knxAddrWrite, bool toggle) {
    WidgetConfig cfg = {};
    cfg.id = id;
    cfg.parentId = -1; // Root
    cfg.type = WidgetType::BUTTON;
    cfg.x = x;
    cfg.y = y;
    cfg.width = 120;
    cfg.height = 50;
    cfg.visible = true;
    cfg.textSource = TextSource::STATIC;
    strncpy(cfg.text, labelText, MAX_TEXT_LEN - 1);
    cfg.fontSize = 1;
    cfg.textAlign = static_cast<uint8_t>(TextAlign::CENTER);
    cfg.isContainer = false;
    cfg.textColor = {255, 255, 255};
    cfg.bgColor = {33, 150, 243}; // Blue
    cfg.bgOpacity = 255;
    cfg.borderRadius = 8;
    cfg.borderWidth = 0;
    cfg.borderColor = {255, 255, 255};
    cfg.borderOpacity = 0;
    cfg.arcMin = 0;
    cfg.arcMax = 100;
    cfg.arcUnit = 0;
    cfg.arcShowValue = true;
    cfg.arcScaleOffset = 0;
    cfg.arcScaleColor = cfg.textColor;
    cfg.arcValueColor = cfg.textColor;
    cfg.arcValueFontSize = cfg.fontSize;
    cfg.themeFixed = false;
    cfg.shadow.enabled = true;
    cfg.shadow.offsetX = 2;
    cfg.shadow.offsetY = 2;
    cfg.shadow.blur = 8;
    cfg.shadow.spread = 0;
    cfg.shadow.color = {0, 0, 0};
    cfg.isToggle = toggle;
    cfg.knxAddressWrite = knxAddrWrite;
    cfg.action = ButtonAction::KNX;
    cfg.targetScreen = 0;
    // Icon defaults
    cfg.iconCodepoint = 0;
    cfg.iconPosition = 0;
    cfg.iconSize = 1;
    cfg.iconGap = 8;
    cfg.iconPositionX = 0;
    cfg.iconPositionY = 0;
    // Secondary/tertiary address defaults
    cfg.knxAddress2 = 0;
    cfg.textSource2 = TextSource::STATIC;
    cfg.text2[0] = '\0';
    cfg.knxAddress3 = 0;
    cfg.textSource3 = TextSource::STATIC;
    cfg.text3[0] = '\0';
    // Conditions
    cfg.conditionCount = 0;
    // Sub-buttons
    cfg.subButtonCount = 0;
    cfg.subButtonSize = 40;
    cfg.subButtonDistance = 80;
    return cfg;
}

// ScreenConfig implementation
void ScreenConfig::clear(uint8_t newId, const char* newName) {
    id = newId;
    mode = ScreenMode::FULLSCREEN;
    backgroundColor = {26, 26, 46}; // Dark blue background
    nightBackgroundColor = {14, 18, 23}; // Darker night background
    bgImagePath[0] = '\0';          // No background image
    bgImageMode = BgImageMode::STRETCH;
    widgetCount = 0;
    memset(widgets, 0, sizeof(widgets));
    memset(name, 0, sizeof(name));
    if (newName && newName[0] != '\0') {
        strncpy(name, newName, sizeof(name) - 1);
    }
    // Modal defaults
    modalX = 0;          // 0 = centered
    modalY = 0;          // 0 = centered
    modalWidth = 0;      // 0 = auto
    modalHeight = 0;     // 0 = auto
    modalBorderRadius = 12;
    modalDimBackground = true;
}

int ScreenConfig::addWidget(const WidgetConfig& widget) {
    if (widgetCount >= MAX_WIDGETS) return -1;

    // Find next free ID
    uint8_t newId = 0;
    for (uint8_t i = 0; i < widgetCount; i++) {
        if (widgets[i].id >= newId) newId = widgets[i].id + 1;
    }

    widgets[widgetCount] = widget;
    widgets[widgetCount].id = newId;
    widgetCount++;
    return newId;
}

bool ScreenConfig::removeWidget(uint8_t id) {
    for (uint8_t i = 0; i < widgetCount; i++) {
        if (widgets[i].id == id) {
            // Shift remaining widgets
            for (uint8_t j = i; j < widgetCount - 1; j++) {
                widgets[j] = widgets[j + 1];
            }
            widgetCount--;
            return true;
        }
    }
    return false;
}

WidgetConfig* ScreenConfig::findWidget(uint8_t id) {
    for (uint8_t i = 0; i < widgetCount; i++) {
        if (widgets[i].id == id) return &widgets[i];
    }
    return nullptr;
}

const WidgetConfig* ScreenConfig::findWidget(uint8_t id) const {
    for (uint8_t i = 0; i < widgetCount; i++) {
        if (widgets[i].id == id) return &widgets[i];
    }
    return nullptr;
}

// GuiConfig implementation
void GuiConfig::clear() {
    screenCount = 0;
    startScreenId = 0;
    standbyEnabled = false;
    standbyScreenId = 0xFF;
    standbyMinutes = 0;
    knxTimeAddress = 0;
    knxDateAddress = 0;
    knxDateTimeAddress = 0;
    knxNightModeAddress = 0;
    screenAnimType = ScreenAnimType::FADE;
    screenAnimDuration = 300;  // Default 300ms
    for (size_t i = 0; i < MAX_SCREENS; i++) {
        screens[i].clear(static_cast<uint8_t>(i), nullptr);
    }
}

ScreenConfig* GuiConfig::findScreen(uint8_t id) {
    for (uint8_t i = 0; i < screenCount; i++) {
        if (screens[i].id == id) return &screens[i];
    }
    return nullptr;
}

const ScreenConfig* GuiConfig::findScreen(uint8_t id) const {
    for (uint8_t i = 0; i < screenCount; i++) {
        if (screens[i].id == id) return &screens[i];
    }
    return nullptr;
}
