#include "ttf_internal.h"
#include <string_utils.h>
#include <memory/heap.h>
#include <serial.h>

// 大端读取器（TTF 为大端格式）
static inline SUINT16 rd16(const SUINT8* p) {
    return ((SUINT16)p[0] << 8) | p[1];
}
static inline SSINT16 rd16s(const SUINT8* p) {
    return (SSINT16)(((SUINT16)p[0] << 8) | p[1]);
}
static inline SUINT32 rd32(const SUINT8* p) {
    return ((SUINT32)p[0] << 24) | ((SUINT32)p[1] << 16) |
           ((SUINT32)p[2] <<  8) |  (SUINT32)p[3];
}

static const SUINT8* find_table(ttf_face_t* face, const char tag[4]) {
    for (SUINT16 i = 0; i < face->num_tables; i++) {
        if (face->tables[i].tag[0] == tag[0] &&
            face->tables[i].tag[1] == tag[1] &&
            face->tables[i].tag[2] == tag[2] &&
            face->tables[i].tag[3] == tag[3]) {
            return face->data + face->tables[i].offset;
        }
    }
    return NULL;
}

// UTF-8 解码
SSINT32 ttf_utf8_decode(const char** p) {
    const SUINT8* s = (const SUINT8*)*p;
    SUINT8 b0 = s[0];
    if (b0 < 0x80)            { (*p)++; return b0; }
    if ((b0 & 0xE0) == 0xC0)  { (*p) += 2; return ((b0 & 0x1F) << 6) | (s[1] & 0x3F); }
    if ((b0 & 0xF0) == 0xE0)  { (*p) += 3; return ((b0 & 0x0F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); }
    if ((b0 & 0xF8) == 0xF0)  { (*p) += 4; return ((b0 & 0x07) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F); }
    (*p)++;
    return -1;
}

// cmap 子表查找
static const SUINT8* find_cmap_subtable(ttf_face_t* face) {
    const SUINT8* cmap = face->cmap;
    SUINT16 num = rd16(cmap + 2);
    const SUINT8* best = NULL;
    SSINT32 best_score = -1;
    for (SUINT16 i = 0; i < num; i++) {
        const SUINT8* rec = cmap + 4 + i * 8;
        SUINT16 platform = rd16(rec + 0);
        SUINT16 encoding = rd16(rec + 2);
        SUINT32 offset   = rd32(rec + 4);
        SSINT32 score = -1;
        if      (platform == 3 && encoding == 10) score = 30;
        else if (platform == 3 && encoding == 1)  score = 20;
        else if (platform == 0 && encoding == 4)  score = 10;
        else if (platform == 0 && encoding == 3)  score = 5;
        if (score > best_score) { best_score = score; best = cmap + offset; }
    }
    return best;
}

static SUINT16 cmap4_lookup(const SUINT8* sub, SSINT32 cp) {
    SUINT16 segCountX2 = rd16(sub + 6);
    SUINT16 segCount   = segCountX2 / 2;
    const SUINT8* endCode    = sub + 14;
    const SUINT8* startCode  = endCode + segCountX2 + 2;
    const SUINT8* idDelta    = startCode + segCountX2;
    const SUINT8* idRangeOff = idDelta + segCountX2;
    for (SUINT16 i = 0; i < segCount; i++) {
        SUINT16 ec = rd16(endCode    + i * 2);
        SUINT16 sc = rd16(startCode  + i * 2);
        if (cp < sc) break;
        if (cp <= ec) {
            SUINT16 dro = rd16(idRangeOff + i * 2);
            if (dro == 0) {
                return (SUINT16)((SSINT16)cp + (SSINT16)rd16(idDelta + i * 2));
            }
            SUINT16 gidx = rd16(idRangeOff + i * 2 + dro + (cp - sc) * 2);
            if (gidx == 0) return 0;
            return (SUINT16)((SSINT16)gidx + (SSINT16)rd16(idDelta + i * 2));
        }
    }
    return 0;
}

static SUINT16 cmap12_lookup(const SUINT8* sub, SSINT32 cp) {
    // Format 12 头：format(2) reserved(2) length(4) language(4) nGroups(4)
    SUINT32 nGroups = rd32(sub + 12);
    const SUINT8* g = sub + 16;
    for (SUINT32 i = 0; i < nGroups; i++) {
        SUINT32 sc = rd32(g + 0);
        SUINT32 ec = rd32(g + 4);
        SUINT32 sG = rd32(g + 8);
        if (cp < (SSINT32)sc) break;
        if (cp <= (SSINT32)ec) return (SUINT16)(sG + (cp - sc));
        g += 12;
    }
    return 0;
}

SUINT16 ttf_cmap_lookup(ttf_face_t* face, SSINT32 cp) {
    const SUINT8* sub = find_cmap_subtable(face);
    if (!sub) return 0;
    SUINT16 fmt = rd16(sub);
    if (fmt == 4)  return cmap4_lookup(sub, cp);
    if (fmt == 12) return cmap12_lookup(sub, cp);
    return 0;
}

// glyf 解码
bool ttf_load_glyph(ttf_face_t* face, SUINT16 glyph_id,
    SUINT32 pixel_size_px, ttf_outline_t* out)
{
    mem_set(out, 0, sizeof(*out));
    if (glyph_id >= face->num_glyphs) return false;

    // Loca 索引
    SUINT32 off0, off1;
    if (face->index_to_loc_format == 0) {
        off0 = ((SUINT32)rd16(face->loca + glyph_id * 2))     * 2;
        off1 = ((SUINT32)rd16(face->loca + (glyph_id + 1) * 2)) * 2;
    } else {
        off0 = rd32(face->loca + glyph_id * 4);
        off1 = rd32(face->loca + (glyph_id + 1) * 4);
    }
    if (off0 >= face->glyf_len) return false;

    // 进宽（始终从 hmtx 读取，无论 glyf 是否存在）
    {
        SUINT16 aw;
        if (glyph_id < face->num_long_hor_metrics) {
            aw = rd16(face->hmtx + glyph_id * 4);
        } else {
            aw = rd16(face->hmtx + (face->num_long_hor_metrics - 1) * 4);
        }
        out->advance = (f26_6)(((SUINT64)aw * (SUINT64)pixel_size_px * 64) / face->units_per_em);
    }

    if (off0 == off1) {
        // 空白字形（如空格）
        return true;
    }

    const SUINT8* g = face->glyf + off0;
    SSINT16 numContours = rd16s(g + 0);
    if (numContours < 0) {
        // 复合字形 — 解析组件记录并合并轮廓
        const SUINT8* cp = g + 10;
        SSINT32 all_xmin = 0x7FFFFFFF, all_ymin = 0x7FFFFFFF;
        SSINT32 all_xmax = -0x7FFFFFFF, all_ymax = -0x7FFFFFFF;

        // 复合字形标志（OpenType 规范）：
        //   0x0001 = ARG_1_AND_2_ARE_WORDS（16 位参数；否则 8 位）
        //   0x0002 = ARGS_ARE_XY_VALUES（偏移量；否则点索引）
        //   0x0008 = WE_HAVE_A_SCALE
        //   0x0040 = WE_HAVE_A_2x2
        //   0x0080 = WE_HAVE_AN_X_AND_Y_SCALE
        //   0x0020 = MORE_COMPONENTS

        for (;;) {
            SUINT16 comp_flags = rd16(cp); cp += 2;
            SUINT16 comp_glyph = rd16(cp); cp += 2;

            // 读取参数（大小取决于 ARG_1_AND_2_ARE_WORDS）
            SSINT32 arg1, arg2;
            if (comp_flags & 0x0001) {
                // 16 位有符号字
                arg1 = rd16s(cp); cp += 2;
                arg2 = rd16s(cp); cp += 2;
            } else {
                // 8 位有符号字节
                arg1 = (SSINT8)cp[0];
                arg2 = (SSINT8)cp[1];
                cp += 2;
            }

            // 如果存在则读取缩放比例
            f26_6 scale = F26_ONE;
            if (comp_flags & 0x0008) {
                // WE_HAVE_A_SCALE：16.16 定点数
                SSINT16 s16 = rd16s(cp); cp += 2;
                scale = (f26_6)s16; // already in f26.6 from 16.16
            }

            // 如果存在则读取 x/y 缩放
            f26_6 scaleX = F26_ONE, scaleY = F26_ONE;
            if (comp_flags & 0x0080) {
                // WE_HAVE_AN_X_AND_Y_SCALE：两个 16.16 值
                SSINT16 sx16 = rd16s(cp); cp += 2;
                SSINT16 sy16 = rd16s(cp); cp += 2;
                scaleX = (f26_6)sx16;
                scaleY = (f26_6)sy16;
            }

            // 如果存在则读取 2x2 矩阵
            f26_6 m00 = F26_ONE, m01 = 0, m10 = 0, m11 = F26_ONE;
            if (comp_flags & 0x0040) {
                // WE_HAVE_A_2x2：四个 2.14 值
                SSINT16 a = rd16s(cp); cp += 2;
                SSINT16 b = rd16s(cp); cp += 2;
                SSINT16 c = rd16s(cp); cp += 2;
                SSINT16 d = rd16s(cp); cp += 2;
                m00 = (f26_6)(a >> 8); // 2.14 -> 26.6: shift right 8
                m01 = (f26_6)(b >> 8);
                m10 = (f26_6)(c >> 8);
                m11 = (f26_6)(d >> 8);
            }

            // 加载组件字形
            ttf_outline_t comp;
            if (!ttf_load_glyph(face, comp_glyph, pixel_size_px, &comp))
                return false;

            // 判断参数是偏移量（XY 值）还是点索引
            SSINT32 offset_x = 0, offset_y = 0;
            if (comp_flags & 0x0002) {
                // ARGS_ARE_XY_VALUES：参数是像素偏移量（已缩放）
                // 从字体单位缩放到像素空间
                offset_x = (SSINT32)(((SSINT64)arg1 * (SSINT64)pixel_size_px * 64 / face->units_per_em));
                offset_y = (SSINT32)(((SSINT64)arg2 * (SSINT64)pixel_size_px * 64 / face->units_per_em));
            }

            // 变换并合并组件点
            for (SUINT16 i = 0; i < comp.num_points; i++) {
                f26_6 fx = comp.x[i];
                f26_6 fy = comp.y[i];
                f26_6 tx, ty;

                if (comp_flags & 0x0040) {
                    // 2x2 矩阵变换
                    tx = f26_mul(m00, fx) + f26_mul(m01, fy);
                    ty = f26_mul(m10, fx) + f26_mul(m11, fy);
                } else if (comp_flags & 0x0008) {
                    // 均匀缩放
                    tx = f26_mul(scale, fx);
                    ty = f26_mul(scale, fy);
                } else if (comp_flags & 0x0080) {
                    // x/y 独立缩放
                    tx = f26_mul(scaleX, fx);
                    ty = f26_mul(scaleY, fy);
                } else {
                    tx = fx;
                    ty = fy;
                }

                f26_6 final_x = tx + offset_x;
                f26_6 final_y = ty + offset_y;

                out->x[out->num_points] = final_x;
                out->y[out->num_points] = final_y;
                out->on_curve[out->num_points] = comp.on_curve[i];
                out->num_points++;
                if (out->num_points > 1024) return false;

                SSINT32 xi = F26_FLOOR(final_x);
                SSINT32 yi = F26_FLOOR(final_y);
                if (xi < all_xmin) all_xmin = xi;
                if (xi > all_xmax) all_xmax = xi;
                if (yi < all_ymin) all_ymin = yi;
                if (yi > all_ymax) all_ymax = yi;
            }

            for (SUINT16 i = 0; i < comp.num_contours; i++) {
                if (out->num_contours >= 64) return false;
                out->first[out->num_contours] = (SUINT16)(out->num_points - comp.num_points + comp.first[i]);
                out->last[out->num_contours]  = (SUINT16)(out->num_points - comp.num_points + comp.last[i]);
                out->num_contours++;
            }

            if (!(comp_flags & 0x0020)) break;  // no more components
        }

        if (out->num_points == 0) return true;
        out->xmin = all_xmin;
        out->ymin = all_ymin;
        out->xmax = all_xmax;
        out->ymax = all_ymax;
        return true;
    }
    if (numContours == 0) return true;
    if (numContours > 64) return false;

    SSINT16 gxMin = rd16s(g + 2);
    SSINT16 gyMin = rd16s(g + 4);
    SSINT16 gxMax = rd16s(g + 6);
    SSINT16 gyMax = rd16s(g + 8);

    const SUINT8* p = g + 10;
    SUINT16 endPts[64];
    for (SSINT16 i = 0; i < numContours; i++) { endPts[i] = rd16(p); p += 2; }
    SUINT16 numPoints = (SUINT16)(endPts[numContours - 1] + 1);
    if (numPoints > 1024) return false;

    SUINT16 instrLen = rd16(p); p += 2;
    p += instrLen;

    // 解码标志（含 REPEAT）
    SUINT8 flags[1024];
    SUINT16 pi = 0;
    while (pi < numPoints) {
        SUINT8 f = *p++;
        flags[pi++] = f;
        if (f & 0x08) {
            SUINT8 rep = *p++;
            for (SUINT16 k = 1; k <= rep && pi < numPoints; k++)
                flags[pi++] = f;
        }
    }

    // 解码 x 坐标到 x_raw[]
    SSINT32 x_raw[1024];
    {
        SSINT32 x = 0;
        for (SUINT16 i = 0; i < numPoints; i++) {
            SUINT8 f = flags[i];
            if (f & 0x02) {
                SUINT8 b = *p++;
                x += (f & 0x10) ? b : -(SSINT32)b;
            } else if (!(f & 0x10)) {
                x += (SSINT16)((SUINT16)p[0] << 8 | p[1]);
                p += 2;
            }
            x_raw[i] = x;
        }
    }
    // 解码 y 坐标到 y_raw[]
    SSINT32 y_raw[1024];
    {
        SSINT32 y = 0;
        for (SUINT16 i = 0; i < numPoints; i++) {
            SUINT8 f = flags[i];
            if (f & 0x04) {
                SUINT8 b = *p++;
                y += (f & 0x20) ? b : -(SSINT32)b;
            } else if (!(f & 0x20)) {
                y += (SSINT16)((SUINT16)p[0] << 8 | p[1]);
                p += 2;
            }
            y_raw[i] = y;
        }
    }

    // 缩放到像素空间（f26_6）
    SUINT64 scale_num = (SUINT64)pixel_size_px * 64;
    for (SUINT16 i = 0; i < numPoints; i++) {
        out->x[i] = (f26_6)(((SSINT64)x_raw[i] * (SSINT64)scale_num) / face->units_per_em);
        out->y[i] = (f26_6)(((SSINT64)y_raw[i] * (SSINT64)scale_num) / face->units_per_em);
        out->on_curve[i] = (flags[i] & 0x01) ? 1 : 0;
    }

    out->num_contours = (SUINT16)numContours;
    out->num_points   = numPoints;
    SUINT16 start = 0;
    for (SSINT16 i = 0; i < numContours; i++) {
        out->first[i] = start;
        out->last[i]  = endPts[i];
        start = endPts[i] + 1;
    }

    out->xmin = (SSINT32)(((SSINT64)gxMin * (SSINT64)scale_num) / face->units_per_em);
    out->ymin = (SSINT32)(((SSINT64)gyMin * (SSINT64)scale_num) / face->units_per_em);
    out->xmax = (SSINT32)(((SSINT64)gxMax * (SSINT64)scale_num) / face->units_per_em);
    out->ymax = (SSINT32)(((SSINT64)gyMax * (SSINT64)scale_num) / face->units_per_em);
    return true;
}

// 打开 / 关闭
ttf_face_t* ttf_open(const void* data, UINTN size) {
    if (!data || size < 12) return NULL;
    const SUINT8* d = (const SUINT8*)data;

    SUINT32 sfVersion = rd32(d);
    if (sfVersion != 0x00010000 && sfVersion != 0x74727565) {
        serial_write("ttf: bad sfVersion\n");
        return NULL;
    }
    SUINT16 numTables = rd16(d + 4);
    if (numTables == 0 || numTables > 32) return NULL;

    ttf_face_t* face = (ttf_face_t*)kcalloc(1, sizeof(ttf_face_t));
    if (!face) return NULL;
    face->data = d;
    face->size = size;
    face->num_tables = numTables;

    for (SUINT16 i = 0; i < numTables; i++) {
        const SUINT8* r = d + 12 + i * 16;
        face->tables[i].tag[0] = r[0];
        face->tables[i].tag[1] = r[1];
        face->tables[i].tag[2] = r[2];
        face->tables[i].tag[3] = r[3];
        face->tables[i].offset = rd32(r + 8);
        face->tables[i].length = rd32(r + 12);
    }

    const SUINT8* head = find_table(face, "head");
    if (!head) { kfree(face); return NULL; }
    face->units_per_em        = rd16(head + 18);
    face->index_to_loc_format = rd16s(head + 50);

    const SUINT8* hhea = find_table(face, "hhea");
    if (!hhea) { kfree(face); return NULL; }
    face->hhea_ascender        = rd16s(hhea + 4);
    face->hhea_descender       = rd16s(hhea + 6);
    face->hhea_line_gap        = rd16s(hhea + 8);
    face->num_long_hor_metrics = rd16(hhea + 34);

    const SUINT8* maxp = find_table(face, "maxp");
    if (!maxp) { kfree(face); return NULL; }
    face->num_glyphs   = rd16(maxp + 4);
    face->max_points   = rd16(maxp + 6);
    face->max_contours = rd16(maxp + 8);

    const SUINT8* os2 = find_table(face, "OS/2");
    if (os2) {
        face->os2_ascender  = rd16s(os2 + 68);
        face->os2_descender = rd16s(os2 + 70);
        face->os2_line_gap  = rd16s(os2 + 72);
    } else {
        face->os2_ascender  = face->hhea_ascender;
        face->os2_descender = face->hhea_descender;
        face->os2_line_gap  = face->hhea_line_gap;
    }

    const SUINT8* loca = find_table(face, "loca");
    const SUINT8* glyf = find_table(face, "glyf");
    const SUINT8* hmtx = find_table(face, "hmtx");
    if (!loca || !glyf || !hmtx) { kfree(face); return NULL; }
    face->loca = loca;
    face->glyf = glyf;
    face->hmtx = hmtx;
    for (SUINT16 i = 0; i < numTables; i++) {
        if (face->tables[i].tag[0]=='g'&&face->tables[i].tag[1]=='l'&&
            face->tables[i].tag[2]=='y'&&face->tables[i].tag[3]=='f')
            face->glyf_len = face->tables[i].length;
        if (face->tables[i].tag[0]=='h'&&face->tables[i].tag[1]=='m'&&
            face->tables[i].tag[2]=='t'&&face->tables[i].tag[3]=='x')
            face->hmtx_len = face->tables[i].length;
    }

    face->cmap = find_table(face, "cmap");
    if (!face->cmap) { kfree(face); return NULL; }

    return face;
}

void ttf_close(ttf_face_t* face) {
    if (face) kfree(face);
}

// 度量值（缩放到 pixel_size，返回 26.6 定点数）
SSINT32 ttf_ascender (ttf_face_t* face, SUINT32 px) {
    return (SSINT32)(((SSINT64)face->os2_ascender  * (SSINT64)px * 64) / face->units_per_em);
}
SSINT32 ttf_descender(ttf_face_t* face, SUINT32 px) {
    return (SSINT32)(((SSINT64)face->os2_descender * (SSINT64)px * 64) / face->units_per_em);
}
SSINT32 ttf_line_gap (ttf_face_t* face, SUINT32 px) {
    return (SSINT32)(((SSINT64)face->os2_line_gap  * (SSINT64)px * 64) / face->units_per_em);
}
