#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
build_grid.py — 72候×7分類(504マス)を「全部埋める」実機ヘッダ生成
------------------------------------------------------------------------
・row0 = 七十二候（data/kigo.json）
・row1..6 = きごさい全5230索引から (季節ブロック×分類) に18語ずつ配置し、504を完全に埋める
           基本季語700を優先採用。足りない分だけ全索引から補う。
・補充語の読み・解説は個別ページから取得（キャッシュ）。解説は24字以内・文末で短縮。

出力: firmware/kigo_font.h, firmware/kigo_data.h（GRID）＋各スケッチへコピー
"""
import os, json, re, shutil
from collections import defaultdict
import make_font as mf
import enrich_kigosai as en   # fetch / parse_yomi / parse_desc を借りる

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CATS = ["時候", "天文", "地理", "生活", "行事", "動物", "植物"]
ROW_CATS = CATS[1:]                       # row1..6
NCOL, NROW = 72, 7
SEASONS = ["春", "夏", "秋", "冬"]
SEASON_BLOCK = {"春": (0, 17), "夏": (18, 35), "秋": (36, 53), "冬": (54, 71)}  # 新年は冬に同居
DESC_MAX = 24
SKETCH_DIRS = ["kigo_pad"]
EXTRA_SYNC = [os.path.expanduser("~/Documents/Arduino/sketch_sep24a")]

def blk(s): return "冬" if s == "新年" else s

def shorten(t, limit=DESC_MAX):
    t = (t or "").strip()
    if len(t) <= limit:
        return t
    cut = t[:limit]
    for p in ("。", "、"):
        i = cut.rfind(p)
        if i >= limit * 0.5:
            return cut[:i+1]
    return cut[:limit-1] + "…"

def main():
    kj = json.load(open(os.path.join(ROOT, "data", "kigo.json"), encoding="utf-8"))
    ko, ko_desc = kj["ko"], kj.get("ko_desc", [""]*72)
    sekki = [s["n"] for s in kj["sekki"]]; phases = kj["phases"]
    ko_season = [SEASONS.index(kj["sekki"][i//3]["s"]) for i in range(72)]

    full = json.load(open(os.path.join(ROOT, "data", "kigosai_index.json"), encoding="utf-8"))
    basic = json.load(open(os.path.join(ROOT, "data", "kigo_basic.json"), encoding="utf-8"))
    basic_ids = set(k["id"] for k in basic)
    enrich = {k["id"]: {"y": k.get("yomi", ""), "d": k.get("desc", "")} for k in basic}  # 既取得

    # プール（季節ブロック×分類）。基本季語を先頭に。
    pool = defaultdict(list)
    for k in full:
        if k["cat"] in ROW_CATS:
            pool[(blk(k["season"]), k["cat"])].append(k)
    for key in pool:
        pool[key].sort(key=lambda k: 0 if k["id"] in basic_ids else 1)  # stable: 基本優先＋索引順

    # 504セル
    GW = [""]*(NCOL*NROW); GY = [""]*(NCOL*NROW); GD = [""]*(NCOL*NROW)
    for c in range(72):
        i = c*NROW; GW[i], GY[i], GD[i] = ko[c][0], ko[c][1], shorten(ko_desc[c])

    selected = []   # 補充で取得が必要な id
    for r, cat in enumerate(ROW_CATS, start=1):
        for season, (lo, hi) in SEASON_BLOCK.items():
            width = hi - lo + 1
            g = pool[(season, cat)][:width]     # 18語（不足時はその数だけ）
            for j, k in enumerate(g):
                col = lo + (round(j*(width-1)/(len(g)-1)) if len(g) > 1 else width//2)
                idx = col*NROW + r
                GW[idx] = k["w"]
                if k["id"] not in enrich:
                    selected.append((idx, k["id"]))
                else:
                    GY[idx] = enrich[k["id"]]["y"]; GD[idx] = shorten(enrich[k["id"]]["d"])

    # 補充語の読み・解説を取得
    print(f"補充取得: {len(selected)} 語 …")
    for n, (idx, kid) in enumerate(selected):
        try:
            h = en.fetch(kid)
            GY[idx] = en.parse_yomi(h); GD[idx] = shorten(en.parse_desc(h))
        except Exception as e:
            print("  !", kid, e)
        if (n+1) % 50 == 0: print(f"  {n+1}/{len(selected)}")

    # フォント
    k32, k16 = set(), set()
    for w in GW: k32 |= set(w); k16 |= set(w)
    for y in GY: k16 |= set(y)
    for d in GD: k16 |= set(d)
    for c in CATS: k16 |= set(c)
    for s in sekki: k16 |= set(s)
    for p in phases: k16 |= set(p)
    k16 |= set("春夏秋冬・「」—")
    k32 = sorted(k32, key=ord); k16 = sorted(k16, key=ord)
    filled = sum(1 for w in GW if w)
    print(f"埋まったマス {filled}/504   font32 {len(k32)}  font16 {len(k16)}")

    font32 = mf.find_font(None, mf.DEFAULT_FONTS); font16 = mf.find_font(None, mf.DEFAULT_FONTS16)
    fp = os.path.join(ROOT, "firmware", "kigo_font.h")
    with open(fp, "w", encoding="utf-8") as f:
        f.write("// AUTOGENERATED by tools/build_grid.py — do not edit.\n#pragma once\n#include <Arduino.h>\n\n")
        mf.emit_glyph_block(f, "GLYPH32", k32, 32, font32, 110)
        mf.emit_glyph_block(f, "GLYPH16", k16, 16, font16, 90)
    dp = os.path.join(ROOT, "firmware", "kigo_data.h")
    with open(dp, "w", encoding="utf-8") as f:
        f.write("// AUTOGENERATED by tools/build_grid.py — do not edit.\n#pragma once\n#include <Arduino.h>\n\n")
        f.write(f"#define NCOL {NCOL}\n#define NROW {NROW}\n\n")
        f.write("const char* const CAT_NAME[NROW] = {" + ",".join(mf.c_str(c) for c in CATS) + "};\n")
        f.write("const char* const SEKKI_NAME[24] = {" + ",".join(mf.c_str(s) for s in sekki) + "};\n")
        f.write("const char* const PHASE_NAME[3]  = {" + ",".join(mf.c_str(p) for p in phases) + "};\n")
        f.write("const char* const SEASON_NAME[4] = {" + ",".join(mf.c_str(s) for s in SEASONS) + "};\n")
        f.write("const uint8_t KO_SEASON[NCOL] = {" + ",".join(str(x) for x in ko_season) + "};\n\n")
        def emit(name, arr):
            f.write(f"const char* const {name}[NCOL*NROW] = {{\n")
            for c in range(NCOL):
                f.write("  " + ",".join(mf.c_str(arr[c*NROW+r]) for r in range(NROW)) + ",\n")
            f.write("};\n")
        emit("GW", GW); emit("GY", GY); emit("GD", GD)
    for t in [os.path.join(ROOT, "firmware", d) for d in SKETCH_DIRS] + EXTRA_SYNC:
        if os.path.isdir(t):
            shutil.copy(fp, os.path.join(t, "kigo_font.h")); shutil.copy(dp, os.path.join(t, "kigo_data.h"))
            print("copied ->", t)

if __name__ == "__main__":
    main()
