# -*- coding: utf-8 -*-
"""Sửa khối kiểm chứng trong mục 09/10 của 'Locqc.md' sau khi kiểm TOÀN BỘ cặp ΔE bằng số học:
các số lẻ (0,16 · 6,96 · 5,40 · 1,61) khớp; 2 KHOẢNG "từ…đến…" không tái lập được."""
import difflib, os, shutil

GOC = r'C:\Claw 2\QC'
TEP = os.path.join(GOC, 'Locqc.md')
BK3 = os.path.join(GOC, '09102026', 'BACKUP_MD', 'Nhan su tham gia', 'QC__Locqc.md_0910_trc_sua-kiemchung.md')

A = '> ⚠️ **Kiểm chứng độc lập bằng số học'
B = '> ⚠️ **Vênh số giữa 2 nguồn'

MOI = """> ⚠️ **Kiểm chứng độc lập bằng số học (Hermes tự tính lại ΔE từ bảng L\\*a\\*b\\* viết tay — kiểm TOÀN BỘ các cặp, không tin bản tự khai):**
> - **Khớp chính xác:** ΔE **0,16** = cặp MDF 1 (Xanh) ↔ MDF 7 (Nâu) ở công đoạn hoàn thiện ✓ · ΔE **6,96** = cặp MDF (Đen) ↔ gỗ thông 1 ở công đoạn primer (tự tính **6,969**; đồng thời là ΔE **lớn nhất** trong toàn bộ 11 nền = 6,97) ✓ · ΔE **5,40** = cặp MDF (Đen) ↔ gỗ Beech 1 (**5,403**) ✓ · ΔE **1,61** = cặp MDF (Đen) ↔ gỗ Beech 1 ở công đoạn hoàn thiện (**1,613**) ✓.
> - **Chưa khớp — cần xác nhận cách tính:** ① công đoạn hoàn thiện ghi "ΔE **0,16 → 1,37**": số 1,37 đúng bằng cặp MDF (Đen) ↔ MDF 1 (Xanh) = 1,377, nhưng nếu so **mọi cặp** giữa 7 nền MDF thì lớn nhất là **1,54** (MDF 5 Trắng ↔ MDF 6 Đen); ② công đoạn primer ghi "ΔE **1,25 → 3,98**": so mọi cặp giữa 7 nền MDF thì nhỏ nhất **0,49** (MDF 2 ↔ MDF 7) và lớn nhất **4,08** (MDF 1 ↔ MDF 6) ⇒ hai khoảng này là **các phép so chọn lọc** (nhiều khả năng so từng nền với một nền/mẫu chuẩn), **không phải biên của toàn bộ ma trận cặp**; ③ riêng câu "nền MDF (Đen) so với **gỗ thông** ΔE 1,61" ở công đoạn hoàn thiện: tự tính MDF (Đen) ↔ gỗ thông 1 = **1,56**, còn 1,61 đúng bằng cặp với **gỗ Beech 1** (1,613).
> - ⇒ **Kết luận kiểm chứng:** các số ΔE nêu riêng lẻ (**0,16 · 1,61 · 5,40 · 6,96**) là **đúng**; chỉ **hai khoảng "từ … đến …" chưa tái lập được** khi so toàn bộ cặp ⇒ cần Lộc/Trí xác nhận cách tính trước khi trích số vào báo cáo tổng hợp.
>
"""

truoc = open(TEP, encoding='utf-8', newline='').read()
i, j = truoc.index(A), truoc.index(B)
assert i < j, 'thứ tự 2 mốc sai'
shutil.copy2(TEP, BK3)
print('backup lần 3:', os.path.basename(BK3), os.path.getsize(BK3), 'B')
print('đoạn cũ bị thay (%d ký tự):' % (j - i))
print('   ' + truoc[i:j].replace('\n', '\n   ')[:400])

moi = truoc[:i] + MOI + truoc[j:]
open(TEP, 'w', encoding='utf-8', newline='').write(moi)

moi = open(TEP, encoding='utf-8', newline='').read()
print()
print('byte TRƯỚC → SAU: %d → %d (%+d)' % (len(truoc.encode()), len(moi.encode()), len(moi.encode()) - len(truoc.encode())))
print('số mục # BÁO CÁO:', truoc.count('\n# BÁO CÁO'), '→', moi.count('\n# BÁO CÁO'))
print('câu cũ còn lại (phải 0):', moi.count('MDF (Đen) so với MDF 1 ở công đoạn'))
seg = moi[moi.rfind('# BÁO CÁO QC — CẬP NHẬT 09/10/2026'):]
for tu in ('1,54', '4,08', '0,49', '1,56', '5,403', '1,613', '6,969', 'ma trận cặp', 'kiểm TOÀN BỘ các cặp'):
    print('   %-26s %s' % (tu, 'CÓ' if tu in seg else 'THIẾU ⚠'))
sm = difflib.SequenceMatcher(None, truoc.split('\n'), moi.split('\n'), autojunk=False)
rem = add = first = None
for tag, i1, i2, j1, j2 in sm.get_opcodes():
    if tag in ('replace', 'delete'):
        rem = (rem or 0) + (i2 - i1); first = i1 if first is None else first
    if tag in ('replace', 'insert'):
        add = (add or 0) + (j2 - j1)
dau_muc = truoc[:truoc.rfind('# BÁO CÁO QC — CẬP NHẬT 09/10/2026')].count('\n')
print('difflib: removed =', rem, '| added =', add, '| dòng sửa đầu tiên =', first, '| mục 09/10 bắt đầu ở dòng', dau_muc,
      '⇒ trong mục 09/10:', first is not None and first >= dau_muc - 1)
