#ifndef UI_H
#define UI_H

#include <Arduino.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#include <LittleFS.h>
#include <U8g2_for_Adafruit_GFX.h>
#include "utils.h"

namespace esp32 {
namespace ui {

// 简易图标：RGB565 像素数组，内存持有
struct Icon {
    uint16_t width = 0;
    uint16_t height = 0;
    uint16_t* pixels = nullptr;  // width*height 大小的 RGB565 数组
};

// 显示操作类型
enum class OpType : uint8_t { FillRect = 0, DrawText = 1, DrawIcon = 2, Line = 3, Circle = 4 };

// 显示项（Display List 条目）
struct DisplayItem {
    OpType op;
    uint16_t key;  // 用于跨帧识别（简化版，当前全量重放）
    int16_t x;
    int16_t y;
    int16_t w;   // FillRect 使用 或 Line/Circle 半径/终点 x
    int16_t h;   // FillRect 使用 或 Line 终点 y
    uint16_t color;  // FillRect/DrawText 使用
    const char* text;  // 指向 textBuf 或字符串字面量
    const Icon* icon;  // DrawIcon 使用
    char textBuf[64];  // 小型文本缓冲，存放动态生成的字符串（例如时间、lap）
};

// 固定容量的显示列表
class DisplayList {
   public:
    static const int MAX_ITEMS = 256; 
    DisplayList() : _count(0) {}

    void clear() { _count = 0; }
    int size() const { return _count; }
    const DisplayItem& at(int i) const { return _items[i]; }

    bool addFillRect(uint16_t key, int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
        if (_count >= MAX_ITEMS) return false;
        auto& it = _items[_count++];
        it.op = OpType::FillRect;
        it.key = key;
        it.x = x; it.y = y; it.w = w; it.h = h; it.color = color;
        it.text = nullptr; it.icon = nullptr;
        return true;
    }

    bool addText(uint16_t key, int16_t x, int16_t y, uint16_t color, const char* text, bool centered = false) {
        if (_count >= MAX_ITEMS) return false;
        auto& it = _items[_count++];
        it.op = OpType::DrawText;
        it.key = key;
        it.x = x; it.y = y; 
        it.w = centered ? 1 : 0;  // w=1 表示需要居中
        it.h = 0; 
        it.color = color;
        // 复制文本到缓冲，保证作用域结束后仍可用
        if (text) {
            strncpy(it.textBuf, text, sizeof(it.textBuf) - 1);
            it.textBuf[sizeof(it.textBuf) - 1] = '\0';
            it.text = it.textBuf;
        } else {
            it.textBuf[0] = '\0';
            it.text = it.textBuf;
        }
        it.icon = nullptr;
        return true;
    }

    bool addIcon(uint16_t key, int16_t x, int16_t y, const Icon* icon) {
        if (_count >= MAX_ITEMS) return false;
        auto& it = _items[_count++];
        it.op = OpType::DrawIcon;
        it.key = key;
        it.x = x; it.y = y; it.w = 0; it.h = 0; it.color = 0;
        it.text = nullptr; it.icon = icon;
        return true;
    }

    bool addLine(uint16_t key, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
        if (_count >= MAX_ITEMS) return false;
        auto& it = _items[_count++];
        it.op = OpType::Line;
        it.key = key;
        it.x = x1; it.y = y1; it.w = x2; it.h = y2; it.color = color;
        it.text = nullptr; it.icon = nullptr;
        return true;
    }

    bool addCircle(uint16_t key, int16_t cx, int16_t cy, int16_t radius, uint16_t color) {
        if (_count >= MAX_ITEMS) return false;
        auto& it = _items[_count++];
        it.op = OpType::Circle;
        it.key = key;
        it.x = cx; it.y = cy; it.w = radius; it.h = 0; it.color = color;
        it.text = nullptr; it.icon = nullptr;
        return true;
    }

   private:
    int _count;
    DisplayItem _items[MAX_ITEMS];
};

// Tween（补间动画）
struct Tween {
    float* target = nullptr;
    float from = 0.0f;
    float to = 0.0f;
    uint32_t startMs = 0;
    uint32_t durationMs = 0;
    float x1 = 0.42f, y1 = 0.0f, x2 = 0.58f, y2 = 1.0f;  // 贝塞尔参数
    bool active = false;
};

// UI 框架主体
class UI {
   public:
    UI() : _tft(nullptr), _u8g2(nullptr), _builder(nullptr), _builderCtx(nullptr) {}

    void begin(Adafruit_ST7735* tft, U8G2_FOR_ADAFRUIT_GFX* u8g2 = nullptr) { 
        _tft = tft; 
        _u8g2 = u8g2;
    }

    // builder: 负责把状态转为显示列表
    using BuilderFn = void (*)(void* ctx, DisplayList& out);
    void setScene(BuilderFn builder, void* ctx) {
        _builder = builder;
        _builderCtx = ctx;
    }

    // 每帧调用：更新动画 + 生成显示列表 + 渲染
    void tick(uint32_t nowMs);

    // 添加一个 float 补间（从当前值到目标值）
    int addTweenFloat(float* target, float to, uint32_t durationMs,
                      float x1 = 0.42f, float y1 = 0.0f, float x2 = 0.58f, float y2 = 1.0f);

    bool hasActiveTweens() const;
    bool isTweenActive(int id) const;

    // 图标加载：文件格式 (little-endian): [2字节宽][2字节高][像素: width*height*2]
    static bool loadIconFromFS(const char* path, Icon& out);
    static void freeIcon(Icon& icon);

    // 启用内存帧缓冲（双缓冲），第一次调用会分配两块 16 位色的画布
    bool enableBackBuffer(uint16_t width, uint16_t height);
    bool isBackBufferEnabled() const { return _useBackBuffer; }

   private:
    void _updateTweens(uint32_t nowMs);
    void _render(const DisplayList& list);
    void _drawIcon(int16_t x, int16_t y, const Icon& icon);
    void _renderToCanvas(const DisplayList& list); // 使用内存画布绘制
    void _flushCanvas();                           // 将当前画布推送到屏幕
    void _swapCanvas();                            // 交换前后缓冲

    Adafruit_ST7735* _tft;
    U8G2_FOR_ADAFRUIT_GFX* _u8g2;
    BuilderFn _builder;
    void* _builderCtx;
    DisplayList _list;

    static const int MAX_TWEENS = 8;
    Tween _tweens[MAX_TWEENS];

    // 双缓冲相关
    bool _useBackBuffer = false;
    GFXcanvas16* _canvasA = nullptr; // 当前绘制目标
    GFXcanvas16* _canvasB = nullptr; // 上一帧
    GFXcanvas16* _canvasCurrent = nullptr;
    GFXcanvas16* _canvasPrev = nullptr;
    uint16_t _bufW = 0;
    uint16_t _bufH = 0;
};

}  // namespace ui
}  // namespace esp32

#endif  // UI_H
