#include "wearable_renderer.h"
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>

struct Draw {std::string text;int x,y,w,h;};
struct Display {
    int pixels=16;std::vector<Draw> drawn;
    void setTextColor(unsigned,unsigned) {}
    void setTextDatum(int) {}
    int fontHeight() const {return pixels;}
    int textWidth(const char* t) const {
        int width=0;
        for(const auto* p=t;*p;++p) {
            const auto c=static_cast<unsigned char>(*p);
            if((c&0xc0)==0x80) continue;
            width+=c<128?(pixels*11+19)/20:pixels;
        }
        return width;
    }
    void drawString(const char* t,int x,int y) {drawn.push_back({t,x,y,textWidth(t),fontHeight()});}
    void fillRoundRect(int x,int y,int w,int h,int,unsigned) {check(x,y,w,h);}
    static void check(int x,int y,int w,int h) {
        for(int px:{x,x+w}) for(int py:{y,y+h}) {
            if((px-234)*(px-234)+(py-233)*(py-233)>217*217) {
                std::fprintf(stderr,"unsafe box x=%d y=%d w=%d h=%d\n",x,y,w,h);assert(false);
            }
        }
    }
    void verify() {for(const auto& d:drawn) check(d.x,d.y,d.w,d.h);drawn.clear();}
    bool has(const char* t) const {for(const auto& d:drawn) if(d.text.find(t)!=std::string::npos) return true;return false;}
};
struct FakeFonts {
    template<class Gfx> void apply(Gfx& g,wearable::TypeRole role,wearable::TextSize size,
                                   unsigned,unsigned=0) const {
        g.pixels=wearable::nominal_pixels(role,size);
    }
};

int main() {
    wearable::UiState ui;ui.boot({});wearable::ShellView v;
    v.selected=true;v.agent="PI";v.project="esp32-dev";v.session="Long session 中文名稱";
    v.model="gpt-5.6-sol";v.effort="high";v.state="RUNNING";v.activity_type="tool";
    v.activity="Running tests...";v.recent="正在检查中文。\nMixed English activity。";
    v.time="18:42";v.date="Sun Oct 04";v.battery="BAT 67%";v.battery_detail="Battery 67%  3.91V";v.firmware="0.6.0";
    Display g;FakeFonts fonts;
    for(auto size:{wearable::TextSize::Compact,wearable::TextSize::Normal,wearable::TextSize::Large}) {
        ui.preferences.text_size=size;
        for(auto theme:{wearable::Theme::Dark,wearable::Theme::Dim}) {
            ui.preferences.theme=theme;
            for(bool online:{false,true}) {
                v.gateway=online;v.wifi=online;
                wearable::ShellRenderer<Display,FakeFonts> renderer(g,fonts,ui,v);
                for(auto rates:{std::pair<float,float>{842,10000},{123400000,98700000},{1e15f,1e18f},{0,0}}) {
                    renderer.monitor({"LIGHTHOUSE",true,18,53,72,rates.first,rates.second});
                    assert(g.has("CPU") && g.has("MEM") && g.has("DISK") && g.has("NET") && g.has("RX") && g.has("TX"));
                    for(const auto& d:g.drawn) if(d.text.rfind("RX",0)==0) assert(d.h==wearable::nominal_pixels(wearable::TypeRole::AgentBodyLarge,size));
                    g.verify();
                }
                renderer.watch();assert(g.has(online?"RUNNING":"OFFLINE"));g.verify();
                renderer.agent();assert(g.has("TOOL ACTIVITY"));g.verify();
                renderer.help();assert(g.has("Wearable Agent Console") && g.has("A  Next page"));g.verify();
                for(auto menu:{wearable::Menu::Root,wearable::Menu::Agent,wearable::Menu::Device,
                              wearable::Menu::Display,wearable::Menu::System}) {
                    ui.menu=menu;
                    for(unsigned i=0;i<ui.items();++i) {ui.index=i;renderer.settings();g.verify();}
                }
                ui.menu=wearable::Menu::Edit;
                for(unsigned i=0;i<5;++i) {ui.field=wearable::Field(i);renderer.settings();g.verify();}
            }
        }
    }
    ui.preferences.text_size=wearable::TextSize::Large;
    v.state="DONE";v.activity_type="text";
    v.final_text="你好，检查已经完成。English result with enough text to require multiple pages.\n第二段很长的结果保持可读取。第三段还是结果。第四段不丢失。";
    std::string seen;
    for(int page=0;page<20;++page) {
        v.now_ms=page*6000;
        wearable::ShellRenderer<Display,FakeFonts>(g,fonts,ui,v).agent();
        for(const auto& line:g.drawn) if(line.y>=181 && line.y<386) seen+=line.text;
        assert(!g.has("Running tests"));g.verify();
    }
    assert(seen.find("不丢失")!=std::string::npos);
    std::puts("Wearable renderer round-safe Watch/Agent/Help/Settings; all sizes/themes; UTF-8 paging PASS");
}
