#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
月次作業記録まとめ → リッチテキスト(.rtf) 生成ツール

用途:
  各顧客の月次作業を「一般の人にわかる業務ベースの箇条書き」に整理した
  内容(JSON)を渡すと、日本語対応のリッチテキスト(.rtf)を書き出す。
  ※内容(要約・平易化)の作成は人/AIが行い、本ツールは整形のみを担う。

使い方:
  python3 worklog_rtf.py --in content.json --out ~/Downloads/作業記録まとめ_2026-07.rtf

出力体裁:
  3階層の番号付きアウトライン（番号は自動採番・青、Word の見出しスタイル風）
    1. 章タイトル                （16pt）
      1.1. 項目見出し            （12pt 太字）
        1) 明細                  （11.5pt）
           ※注記                 （10pt・番号なし）
  ※ h2 / head に手書きの番号("1. ")や中黒("● ")が入っていても自動で取り除く。

content.json の形式:
{
  "title": "作業記録まとめ 2026年7月",
  "intro": "2026年7月に実施した …（1段落の概要）",
  "sections": [
    {
      "h2": "メルシーダイキ ― 介護用具の在庫・レンタル管理",
      "entries": [
        {
          "head": "〇〇を改善（7/3）",
          "bullets": ["…した。", "…も対応。"],
          "subs": ["※本番公開は次段階の予定。"]   // 任意
        }
      ]
    }
  ]
}

検証:
  textutil -convert txt -stdout <出力.rtf>   でプレーンテキスト化して内容確認できる。
"""
import json, os, argparse, re

# 手書きの見出し装飾（先頭の "1. " "1.2. " "● " "★ " 等）を除去して自動採番に委ねる
# 番号は "1. " / "2.3. " のように末尾ピリオド＋空白がある場合のみ除去
# （"7月4日 Ｚシステム会議" の先頭数字を巻き込まないため）
_LEAD = re.compile(r'^(?:[0-9]+(?:\.[0-9]+)*\.\s+|[●○◆■・★☆]\s*)+')

def strip_lead(s):
    return _LEAD.sub('', s).strip()

def esc(s):
    """任意のUnicode文字列をRTFエスケープ(非ASCIIは \\uN? 形式)"""
    out = []
    for ch in s:
        o = ord(ch)
        if ch == '\\': out.append('\\\\')
        elif ch == '{': out.append('\\{')
        elif ch == '}': out.append('\\}')
        elif o < 128: out.append(ch)
        else:
            if o > 0xFFFF:
                o2 = o - 0x10000
                for u in (0xD800 + (o2 >> 10), 0xDC00 + (o2 & 0x3FF)):
                    if u > 32767: u -= 65536
                    out.append('\\u%d?' % u)
            else:
                u = o
                if u > 32767: u -= 65536
                out.append('\\u%d?' % u)
    return ''.join(out)

def build_rtf(doc):
    p = []
    p.append(r"{\rtf1\ansi\ansicpg65001\deff0")
    # BIZ UDGothic（ユニバーサルデザイン書体・macOS標準搭載）。無い環境では代替に落ちる
    p.append(r"{\fonttbl{\f0\fnil\fcharset128 BIZ UDGothic;}{\f1\fnil\fcharset128 Hiragino Sans;}}")
    # cf1=黒本文 / cf2=番号の青 / cf3=見出しの濃紺
    p.append(r"{\colortbl;\red0\green0\blue0;\red46\green116\blue181;\red31\green56\blue100;}")
    p.append(r"\f0\fs24")
    if doc.get("title"):
        p.append(r"\pard\qc\sb0\sa200\b\fs40\cf3 " + esc(doc["title"]) + r"\cf1\b0\par")
    if doc.get("intro"):
        p.append(r"\pard\sb0\sa240\fs22\i\cf1 " + esc(doc["intro"]) + r"\i0\par")

    for i, sec in enumerate(doc.get("sections", []), 1):
        # レベル1: 「1. 章タイトル」16pt
        if sec.get("h2"):
            p.append(r"\pard\sb320\sa100\fi-440\li440\fs32 "
                     + r"{\cf2 %d.}\tab " % i
                     + r"{\cf1 " + esc(strip_lead(sec["h2"])) + r"}\par")
        for j, e in enumerate(sec.get("entries", []), 1):
            # レベル2: 「1.1. 項目見出し」12pt 太字
            if e.get("head"):
                p.append(r"\pard\sb160\sa40\fi-460\li900\b\fs24 "
                         + r"{\cf2 %d.%d.}\tab " % (i, j)
                         + r"{\cf3 " + esc(strip_lead(e["head"])) + r"}\b0\par")
            # レベル3: 「1) 明細」10.5pt
            for k, bl in enumerate(e.get("bullets", []), 1):
                p.append(r"\pard\sb0\sa40\fi-460\li1460\fs23 "
                         + r"{\cf2 %d)}\tab " % k
                         + r"{\cf1 " + esc(bl) + r"}\par")
            # 注記: 番号なし・明細と同じ字下げ
            for su in e.get("subs", []):
                p.append(r"\pard\sb0\sa40\fi0\li1460\fs20\cf1 " + esc(su) + r"\par")
    p.append("}")
    return "\n".join(p)

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--in", dest="infile", required=True, help="content JSON path")
    ap.add_argument("--out", dest="outfile", required=True, help="output .rtf path")
    a = ap.parse_args()
    with open(os.path.expanduser(a.infile), encoding="utf-8") as f:
        doc = json.load(f)
    rtf = build_rtf(doc)
    out = os.path.expanduser(a.outfile)
    with open(out, "w", encoding="ascii") as f:
        f.write(rtf)
    print("WROTE", out, "(", len(rtf), "bytes )")

if __name__ == "__main__":
    main()
