#pragma once

#include "M5GFX.h"
#include "glyph_metrics_cache.h"
#include "esp_heap_caps.h"

// STT may return simplified, traditional, or mixed Chinese. Keep the original
// transcript and use the traditional font only for glyphs absent from CN.
class TranscriptFont final : public lgfx::IFont {
public:
    ~TranscriptFont() { heap_caps_free(cache_); }
    void getDefaultMetric(lgfx::FontMetrics *metrics) const override {
        lgfx::fonts::efontCN_16.getDefaultMetric(metrics);
    }

    bool updateFontMetric(lgfx::FontMetrics *metrics, uint16_t code) const override {
        return select(metrics,code)!=nullptr;
    }

    size_t drawChar(lgfx::LGFXBase *gfx, int32_t x, int32_t y, uint16_t code,
                    const lgfx::TextStyle *style, lgfx::FontMetrics *metrics,
                    int32_t &filled_x) const override {
        lgfx::FontMetrics probe=*metrics;
        const auto* font=select(&probe,code);
        if(!font)font=&lgfx::fonts::efontTW_16;
        return font->drawChar(gfx,x,y,code,style,metrics,filled_x);
    }
private:
    using Cache=wearable::GlyphMetricsCache<lgfx::IFont>;
    const lgfx::IFont* select(lgfx::FontMetrics* metrics,uint16_t code) const {
        if(!cache_)cache_=static_cast<Cache::Entry*>(heap_caps_calloc(Cache::slots,sizeof(Cache::Entry),MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT));
        if(const auto* entry=Cache::find(cache_,code)) {
            if(entry->font) {
                metrics->width=entry->width;metrics->x_advance=entry->advance;metrics->x_offset=entry->offset;
            }
            return entry->font;
        }
        const lgfx::IFont* font=nullptr;
        if(lgfx::fonts::efontCN_16.updateFontMetric(metrics,code))font=&lgfx::fonts::efontCN_16;
        else if(lgfx::fonts::efontTW_16.updateFontMetric(metrics,code))font=&lgfx::fonts::efontTW_16;
        Cache::put(cache_,code,font,metrics->width,metrics->x_advance,metrics->x_offset);
        return font;
    }
    mutable Cache::Entry* cache_=nullptr;
};
