# -*- coding: utf-8 -*-
"""第5回 PDF「確認事項（第5回）」の自己点検。

原稿 (docs/handoff/TeamWorks確認事項_第5回_20260907.md) の文言が
すべて PDF に含まれているか、フォントが日本語フォントで埋め込まれているかを見る。
PDF のパスは第1引数で渡せる。省略時はこのスクリプトと同じディレクトリ。

check_teamworks_qa4_pdf.py（第4回用）と同じ構成。

★must に「ページを跨ぐ語」を入れないこと★
抽出テキストにフッター（D-Watch / DFA Robotics とページ番号）が挟まり、
空白を詰めても一致しません。第3回で bigint auto_increment が実際に引っかかりました。

★この点検では表の列幅崩れ（識別子が語の途中で折り返る）は検出できません★
生成後に全ページを目視確認すること（pdf/README.md）。
"""
import os
import re
import sys

from pypdf import PdfReader

PDF = (sys.argv[1] if len(sys.argv) > 1 else
       os.path.join(os.path.dirname(os.path.abspath(__file__)),
                    "DWatch_確認事項_第5回_20260907.pdf"))
if not os.path.exists(PDF):
    raise SystemExit("PDF が見つからない: %s\n"
                     "先に make_teamworks_qa5_pdf.py を実行するか、"
                     "PDF のパスを第1引数で渡すこと。" % PDF)

raw = open(PDF, "rb").read()
reader = PdfReader(PDF)
pages = [p.extract_text() for p in reader.pages]
text = "\n".join(pages)
flat = re.sub(r"\s+", "", text)

print("== 1. ページ数とサイズ ==")
print("ページ数:", len(reader.pages), " サイズ:", len(raw), "bytes",
      "(%.1f KB)" % (len(raw) / 1024))
print("抽出文字数:", len(text))

print("\n== 2. フォント埋め込み ==")
print("/FontFile2 出現回数:", raw.count(b"/FontFile2"))
biz = sorted(set(re.findall(rb"/([A-Z]{6}\+[A-Za-z0-9\-]*BIZ[A-Za-z0-9\-]*)", raw)))
print("BIZUDGothic を含むフォント名:", biz)
if not biz:
    print("  ★NG★ BIZ UDGothic が埋め込まれていない")
# 中国語向けフォントが混ざっていないこと（CLAUDE.md §0-3）
CN = [b"SimSun", b"SimHei", b"MicrosoftYaHei", b"MSYaHei",
      b"NotoSansSC", b"NotoSerifSC", b"SourceHanSansSC", b"SourceHanSerifSC"]
hit = [n.decode() for n in CN if n in raw]
print("中国語向けフォント:", hit if hit else "混入なし")
if hit:
    print("  ★NG★ 中国語向けフォントが混ざっている")

print("\n== 3. 原稿の全項目が含まれるか ==")
must = [
    # 表題・前文
    "確認事項（第5回）", "TeamWorks（DB開発側）",
    "作成日:2026-09-07", "DFARobotics",
    "第3回・第4回のご回答をありがとうございました", "すべて反映しています",
    "本書は次の5部構成です",
    # サマリ表
    "解決した件のご共有", "最新のDDLのお願い", "週の帰属についての確認",
    "エラー情報についての確認", "継続と保留",
    "回答不要", "定義書の備考欄が空で、値が分かりません",
    "B-1・B-2は保留で了解しております",
    # 1. 共有
    "W-1（月跨ぎ週）", "いただいたルールをそのまま採用しました",
    "週を月境界で分割する", "8月第6週", "9月第1週", "9月第2週",
    "2026/8/1は1日だけでも", "8月第1週",
    "全252か月で総当たりして検証",
    "書式）—解決しました", "区切りはカンマ", "1〜3599",
    "テーブル定義書の備考欄に最初から明記されていました",
    "こちらの確認漏れでした", "以後、書式や値域は定義書を先に確認します",
    "ビューアー側で持つことにしました",
    "運用担当が書き留めるメモ", "DFA側の独自ストアに保存する",
    "メインDBには書き込みません", "DB側の対応は不要です",
    # 2. DDL
    "最新のDDLをいただけますでしょうか",
    "対応済み", "入っていませんでした",
    "全文差分", "制約名の全文検索",
    "A-1", "A-3", "B-3b", "未反映",
    "主キーをerror_idにする", "timestamp系のDEFAULT",
    "その日のうちに照合してご報告します",
    # 3-X-1
    "第6週はどう格納されますか",
    "第1週1,第2週2,第3週3,第4週4,第5週5",
    "0は月の集計値を表す",
    "定義書の1〜5では第6週を表現できません",
    "第6週はカレンダー上、実際に発生します",
    "31日月で1日が金曜または土曜、または30日月で1日が土曜",
    "28日・29日月では発生しません",
    "55か月＝年平均2.6回",
    "2026年5月と8月は、すでに過ぎた月です",
    "2025-03", "2026-05", "2026-08", "2027-10",
    "すでに格納先が必要になっている",
    "この範囲は1〜2日しかないため、欠けても気づきにくいです",
    "総量としては目立たず数字が落ちます",
    "08-23〜08-31の9日間",
    "当方の画面と貴社のサマリで数字が食い違う形になります",
    "参考:2026年8月の週の切れ目（全6週）",
    "第1週と第6週の両方が短くなります",
    "お伺いしたいこと", "次のどちらでしょうか",
    "定義書が古く、weekに6が入る",
    "第6週は別の扱いになる",
    "第5週に含める", "行を作らない",
    "weekの上限を6として実装します",
    "上限5では表現できない期間が生じる",
    "week=6の行が来る前提",
    "月の集計値",
    "6は物理的に格納できます",
    "Aであれば当方はこのまま進められます",
    "定義書の備考の更新をお願いできますでしょうか",
    "Bの場合は、当方の実装をやり直すことになります",
    "第6週にあたる期間の数字がどこに入っているか",
    # 3-X-2
    "年の集計値", "定義書の備考から、次のように読み取りました",
    "粒度を判別する",
    "違っている場合のみ",
    "P1では読みません",
    "レポート画面は週次・月次のみのためです",
    # 3-X-3
    "2行になりますか",
    "矛盾していませんか",
    "いただいたルールの当然の帰結",
    "バッチの実装がそうなっているか",
    "2つの単位が一致しないことです",
    "バッチの対象定義", "サマリの格納単位",
    "7日で1本", "月をまたぐと2本",
    "格納先は2行に分かれる",
    "前週の8月分", "前週の9月分",
    "1回のバッチで2行が作られるという理解でよいでしょうか",
    "寄せなかった側の期間の数字が欠けます",
    "データなし",
    "運用後の課題になります", "この点は回答不要です",
    # 4. エラー情報
    "エラー情報についての確認（3件）",
    "待機中・充電中はrobots.status",
    "当方で対応表を作る前提で準備しています",
    "備考欄がいずれも空欄で、格納される値が分かりませんでした",
    "対応表のキーが決まらない",
    "入る値の「形」を教えてください",
    "対応表のキーが変わります",
    "数値を文字列で", "コード名（英字）", "日本語の名称",
    "コードと名称の組み合わせ",
    "実際に入っている値を1〜2件",
    "推測は避けたいです",
    "空文字やNULLになるケースがあるか",
    "未知の値は「その他」に寄せる",
    "空の場合も「その他」に寄せてよいか",
    "入る値の一覧を教えてください",
    "定義書の備考欄が空",
    "英字の区分でしょうか",
    "PUDU側の区分をそのまま入れているのでしょうか",
    "画面の重要度表示や並び順に使いたい",
    "どちらが重いか",
    "サマリ側のerror_typeは明細と同じ値域ですか",
    "1行=1エラー種別×期間の集計行",
    "同じ値が入るという理解でよいでしょうか",
    "明細とサマリの両方で使えます",
    "サマリ側の値の一覧もお教えください",
    "エラー種別の内訳",
    "明細とサマリの数字が突き合わせられなくなります",
    "何が入るか",
    "長さの目安",
    # 5. 継続と保留
    "DB更新用アカウントの発行",
    "のみUPDATE可",
    "発行の見込みをお教えいただけますでしょうか",
    "作業は止まっていません",
    "実DBへの接続に進む段階で必要になります",
    "保留で了解しているもの",
    "後で登録する",
    "保留で了解しております",
    "DDLの再受領時にあわせて確認します",
    # 末尾
    "おわりに",
    "優先度をつけるとすれば次の順です",
    "Bの場合、当方の実装をやり直すことになります",
    "受領後、当方でその日のうちに照合します",
    "ハンドルアップ", "緊急停止", "オフライン",
    "重要度表示と、レポートのエラー内訳に使います",
    "確認のみ",
    "実DB接続の段階で必要になります",
    "引き続きよろしくお願いします",
]

miss = [m for m in must if re.sub(r"\s+", "", m) not in flat]
print("検査項目:", len(must), " 欠落:", len(miss))
for m in miss:
    print("  ★欠落★", m)

print("\n== 4. 判定 ==")
ok = (not miss) and bool(biz) and (not hit)
print("結果:", "OK" if ok else "NG")
sys.exit(0 if ok else 1)
