# 公開中の Google スプレッドシート・ドキュメントの埋め込み15本を、サイトの中の表と本文に置き換える（2026-11-08）
# 使い方: python3 build2.py <public/embeds のフォルダ>
import csv, html, re, sys, importlib.util
from html.parser import HTMLParser
OUT = sys.argv[1]
G = '/tmp/claude-0/gs/'
spec = importlib.util.spec_from_file_location('b1', '/tmp/claude-0/sheets/build.py')
src = open('/tmp/claude-0/sheets/build.py', encoding='utf-8').read()
CSS = re.search(r'CSS = """(.*?)"""', src, re.S).group(1)
JS = open('/tmp/claude-0/sheets/height.js', encoding='utf-8').read()
CSS = CSS.replace('</style>', """th{white-space:normal}
.blk+.blk{margin-top:28px}
td.g{background:#f7f7f7;font-weight:700;font-size:12px;padding:8px 10px;border-bottom:0}
.doc{font-size:14px;line-height:1.85}
.doc h1,.doc h2,.doc h3,.doc h4{font-size:16px;line-height:1.5;margin:24px 0 8px}
.doc h1:first-child,.doc h2:first-child,.doc h3:first-child{margin-top:0}
.doc p{margin:0 0 6px}
.doc ul,.doc ol{margin:0 0 10px;padding-left:1.4em}
.doc li{margin:0 0 2px}
@media (max-width:560px){ .auto td.g::before{display:none} .auto tr.g{background:none;padding:12px 0 4px;margin:0} .auto tr.g td{background:none;padding:0} }
</style>""")
e = html.escape


def head(title):
    return ('<!doctype html>\n<html lang="ja">\n<head>\n<meta charset="utf-8">\n'
            '<meta name="viewport" content="width=device-width,initial-scale=1">\n'
            '<title>%s</title>\n<link rel="preconnect" href="https://fonts.googleapis.com">\n'
            '<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">\n'
            '%s\n</head>\n<body>\n<div class="wrap">\n') % (e(title), CSS)


def tail(note=None):
    n = '<p class="src">%s</p>\n' % e(note) if note else ''
    return n + '</div>\n' + JS + '\n</body>\n</html>\n'


def clean(v):
    return v.replace('￨', 'ー').strip()


def blocks(rows):
    out, cur = [], []
    for r in rows:
        r = [clean(c) for c in r]
        if not any(r):
            if cur: out.append(cur); cur = []
        else:
            cur.append(r)
    if cur: out.append(cur)
    return out


def table(rows, lab=None):
    n = max(len(r) for r in rows)
    rows = [r + [''] * (n - len(r)) for r in rows]
    title = None
    # 1つ目の行が「見出しだけ」（先頭の欄だけ）なら、表の名前にする
    if sum(1 for c in rows[0] if c) == 1 and rows[0][0] and len(rows) > 1:
        title = rows[0][0]; rows = rows[1:]
    # 先頭の列が見出しの行にしか無いなら、それは表の名前
    if rows[0][0] and len(rows) > 1 and not any(r[0] for r in rows[1:]) and any(c for c in rows[0][1:]):
        title = title or rows[0][0]
        rows = [r[1:] for r in rows]
    keep = [i for i in range(len(rows[0])) if any(r[i] for r in rows)]
    rows = [[r[i] for i in keep] for r in rows]
    hd, body = rows[0], rows[1:]
    # 先頭が番号だけの列なら、名前の列の頭に付けて1つにする（カードの見出しを名前にするため）
    if body and all(re.fullmatch(r'\d+', r[0] or 'x') for r in body):
        k = next((i for i, h in enumerate(hd) if '名' in h), None)
        if k:
            for r in body: r[k] = r[0] + '　' + r[k]
            order = [k] + [i for i in range(1, len(hd)) if i != k]
            hd = [hd[i] for i in order]; body = [[r[i] for i in order] for r in body]
    avg = sum(len(c) for r in body for c in r) / max(1, sum(len(r) for r in body))
    mode = 'stack' if len(hd) >= 6 or (len(hd) == 5 and avg > 16) else 'auto'
    th = ''.join('<th>%s</th>' % e(h) for h in hd)
    trs = []
    for r in body:
        if sum(1 for c in r if c) == 1 and r[0]:
            trs.append('<tr class="g"><td class="g" colspan="%d">%s</td></tr>' % (len(hd), e(r[0]))); continue
        tds = ''.join('<td%s data-h="%s">%s</td>' % (' class="k"' if i == 0 else '', e(h), e(v).replace('\n', '<br>')) for i, (h, v) in enumerate(zip(hd, r)))
        trs.append('<tr>' + tds + '</tr>')
    t = title or lab
    return ('<div class="blk %s">%s<table><thead><tr>%s</tr></thead><tbody>\n%s\n</tbody></table></div>\n'
            % (mode, '<p class="lab">%s</p>' % e(t) if t else '', th, '\n'.join(trs)))


def sheet_page(fname, name, csvs, note=None):
    body = ''
    for i, c in enumerate(csvs):
        bl = blocks(list(csv.reader(open(G + c, encoding='utf-8'))))
        for j, b in enumerate(bl):
            body += table(b, lab=(name[i] if isinstance(name, list) else name) if j == 0 else None)
    t = name[0] if isinstance(name, list) else name
    open('%s/%s.html' % (OUT, fname), 'w', encoding='utf-8').write(head(t) + body + tail(note))


class Doc(HTMLParser):
    KEEP = {'h1', 'h2', 'h3', 'h4', 'p', 'ul', 'ol', 'li', 'table', 'tr', 'td', 'br', 'strong', 'b'}
    def __init__(self):
        super().__init__(); self.out = []; self.on = False; self.skip = 0
    def handle_starttag(self, t, a):
        a = dict(a)
        if a.get('id') == 'contents': self.on = True; return
        if not self.on: return
        if t in ('style', 'script'): self.skip += 1
        if t in self.KEEP: self.out.append('<%s>' % t)
    def handle_endtag(self, t):
        if not self.on: return
        if t in ('style', 'script'): self.skip -= 1
        if t in self.KEEP and t != 'br': self.out.append('</%s>' % t)
    def handle_data(self, d):
        if self.on and not self.skip: self.out.append(e(d))


def doc_page(fname, title, path):
    p = Doc(); p.feed(open(G + path, encoding='utf-8').read())
    h = ''.join(p.out)
    h = re.sub(r'<p>\s*</p>', '', h); h = re.sub(r'<(\w+)>\s*</\1>', '', h)
    open('%s/%s.html' % (OUT, fname), 'w', encoding='utf-8').write(head(title) + '<div class="doc">%s</div>\n' % h + tail())


sheet_page('day18-3QlV0Qdj', 'Figma-カラー/機能', ['day18-3QlV0Qdj.csv'])
sheet_page('day18-s8a8NqF2', 'Figma-カラー/バリアブル運用', ['day18-s8a8NqF2.csv'])
sheet_page('day20-opjVEsl9', 'ROS「ノード」', ['day20-opjVEsl9.csv'])
sheet_page('day20-wWuDrA1m', 'UnityxROS解説', ['day20-wWuDrA1m.csv'])
sheet_page('day21-rHvWywD8', 'ROS 2 基本コマンド（エラー対応メモ）', ['day21-rHvWywD8.csv'])
sheet_page('day22-q3Z4LUDY', ['P2M テックログ：ROS 2 基本コマンド（エラー対応メモ）', 'P2M テックログ：デバック情報まとめ'], ['t1035248351.csv', 't220498241.csv'])
sheet_page('day25-LBQh79h4', 'Unity-視点操作ガイド', ['day25-LBQh79h4.csv'])
sheet_page('day31-jdGUh_aI', 'ロボティクスUXデザイナー戦略', ['day31-jdGUh_aI.csv'])
sheet_page('day33-R9vno25x', 'フィジカルAIによるパラダイムシフト', ['day33-R9vno25x.csv'])
sheet_page('day34-kFbqYm6g', 'フェーズ3', ['day34-kFbqYm6g.csv'])
sheet_page('day37-5nNtmwHN', 'フェーズ3', ['day37-5nNtmwHN.csv'])
sheet_page('day43-DNB5IfRA', '使用するツールセット', ['day43-DNB5IfRA.csv'])
sheet_page('day43-rk6cAPq3', '実験用パラメーター表', ['day43-rk6cAPq3.csv'])
sheet_page('day51-PCdp7_Yb', 'FigJam-ライブラリ部品', ['day51-PCdp7_Yb.csv'])
doc_page('day78-XSSoeDI1', 'デジタルツイン学習-R2R2R LP構成素案', 'd78.html')
print('ok')
