# -*- coding: utf-8 -*-
"""Dựng báo cáo gửi anh: ĐỀ XUẤT CÔNG THỨC MÀU NỀN (Dye + Pigment, CSDL B).
Gồm: số đo code · mục tiêu · 2 PA của AGY (nguyên văn mục D) · KIỂM CHỨNG độc lập bằng code
(cho thấy PA của AGY lệch màu) · PA hiệu chỉnh tỉ lệ theo đúng bộ mã AGY · PA tìm bằng code (F3RK)
· cách pha + 4 ô thử · điểm cần xác nhận."""
import io, json, os
from datetime import datetime

B = r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze'
D = os.path.join(B, 'phan-tich-nen-mau-07-10')
DO = json.load(io.open(os.path.join(B, 'anh_lo09_nen_mau', '_do_mau_nen_v2_20261007.json'), encoding='utf-8'))
TK = json.load(io.open(os.path.join(D, '_ket_qua_phoi_mau_TONKHO.json'), encoding='utf-8'))
HC = json.load(io.open(os.path.join(D, '_ket_qua_hieu_chinh_theo_bo_ma_agy.json'), encoding='utf-8'))
AGY = os.path.join(D, '_agy_cong_thuc_nen_mau.md')
agy = io.open(AGY, encoding='utf-8', errors='replace').read() if os.path.exists(AGY) else ''


def doc_dau(md):
    """Cắt phần D (2 phương án) của AGY để đưa vào phụ lục + làm sạch ký hiệu LaTeX."""
    i = md.find('## D. HAI PHƯƠNG ÁN')
    j = md.find('## E.')
    t = md[i:j].strip() if i >= 0 else ''
    thay = [(u'\\Delta L^*', u'ΔL*'), (u'\\Delta a^*', u'Δa*'), (u'\\Delta b^*', u'Δb*'),
            (u'\\Delta E^*', u'ΔE'), (u'\\Delta E', u'ΔE'), (u'\\text', u''), (u'\\%', u'%'),
            (u'$', u''), (u'{', u''), (u'}', u''), (u'P10 \\to P90', u'P10 → P90'), (u'\\to', u'→'),
            (u'TiO_2', u'TiO₂'), (u'L^*', u'L*'), (u'a^*', u'a*'), (u'b^*', u'b*'), (u'\\approx', u'≈'),
            (u'\\times', u'×'), (u'\\text{g}', u'g'), (u'\\mu', u'µ'),
            (u'| :--- | :---: | :---: | :--- | :--- |', u'|---|---|---|---|---|'),
            (u'| :--- | :--- |', u'|---|---|')]
    for a, b_ in thay:
        t = t.replace(a, b_)
    return t


L = []
A = L.append
A(u'# ĐỀ XUẤT CÔNG THỨC MÀU NỀN NHUỘM GỖ — HỆ DYE + PIGMENT (CSDL B)')
A(u'')
A(u'- Ngày: %s · Dự án B (CSDL B: `CSDLB.db`)' % datetime.now().strftime('%d/%m/%Y'))
A(u'- Ảnh: mẫu đã lên màu + gỗ mộc (anh gửi 07/10/2026)')
A(u'- Số màu: **đo bằng code** (trung vị pixel trong mặt nạ màu → CIELAB D65). Phần phân tích màu do **AGY** thực hiện, '
  u'em **kiểm chứng lại bằng code** trước khi gửi anh.')
A(u'')
A(u'## 1. Số đo màu (code)')
A(u'')
A(u'| Ảnh | Màu trung vị | L* | a* | b* | Dải vân P10→P90 |')
A(u'|---|---|---|---|---|---|')
A(u'| Mẫu đã lên màu | %s | %.1f | %+.1f | %+.1f | %.1f → %.1f |' % (DO['mau']['hex'], DO['mau']['L'], DO['mau']['a'], DO['mau']['b'], DO['mau']['L_p10'], DO['mau']['L_p90']))
A(u'| Gỗ mộc | %s | %.1f | %+.1f | %+.1f | %.1f → %.1f |' % (DO['moc']['hex'], DO['moc']['L'], DO['moc']['a'], DO['moc']['b'], DO['moc']['L_p10'], DO['moc']['L_p90']))
A(u'')
A(u'**Cần đạt:** hạ sáng **%.1f L\\*** · đẩy đỏ **+%.1f a\\*** · đẩy vàng **+%.1f b\\*** — vẫn nhìn thấy vân (nhuộm ngấm, không che kín).'
  % (abs(DO['delta']['dL']), DO['delta']['da'], DO['delta']['db']))
A(u'')
A(u'⚠️ Ảnh **không có thẻ màu chuẩn** ⇒ số tuyệt đối có thể lệch vài đơn vị L*; dùng để so sánh. Muốn chốt phải đo mẫu vật lý / so thẻ màu.')
A(u'')
A(u'## 2. Hai phương án AGY đề xuất (nguyên văn mục D)')
A(u'')
A(u'**PA1 — hệ lai DYE + PIGMENT:** `Nâu BS1008 (1-1)DM (5%)` 55% + `Đỏ VM334 (5%)` 28% + `MH Black 20 (Solvent Black 27)` 12% + `Vàng Y57 (5%)` 5%; '
  u'nồng độ **6,0%** trong dung dịch; nhuộm ngấm lau trực tiếp trên gỗ mộc, lau dọc vân.')
A(u'**PA2 — 100% PIGMENT/oxit trong suốt:** `Nâu BS1008 (1-1)DM (10%)` 60% + `Đỏ RS718 (1-1)DM (10%)` 25% + `Đen BT M100S (1-0.5) DM (2%)` 10% + `Vàng YB 87 (1-1)DM (5%)` 5%; '
  u'nồng độ **5,5%**; cũng nhuộm ngấm lau trực tiếp.')
A(u'')
A(u'Điểm mạnh của 2 PA: chọn đúng hướng — **màu nâu gỗ làm nền (TB 1008/BS1008) + đỏ oxide/dye để đẩy a\\* + một ít đen để hạ sáng + vài % vàng cân ấm**; '
  u'đều là mã **có tồn kho** (TB 1008 1.047,5 kg · TR 718 298,5 kg · MA 100 430 kg · YB-2087 800 kg).')
A(u'')
A(u'## 3. KIỂM CHỨNG ĐỘC LẬP — 2 PA của AGY lệch màu khá nhiều')
A(u'')
A(u'Em dựng lại đúng thành phần/đúng tỉ lệ AGY ghi, lấy **số màu các ô in tương ứng trong CSDL B**, tính hỗn hợp bằng mô hình '
  u'Kubelka-Munk rồi phủ lên màu gỗ mộc đo được:')
A(u'')
A(u'| Phương án AGY | Màu dự kiến (code tính lại) | Lệch so mục tiêu | Nhận xét |')
A(u'|---|---|---|---|')
A(u'| PA1 (thay ô đen bằng ô đen gần nhất vì `MH Black 20` không có ô in) | L* 52–55 · a* +28…+35 · b* +21…+26 | **ΔE 22–28** | Quá sáng, **quá đỏ và quá vàng** |')
A(u'| PA2 (đủ số liệu ô in) | L* 48–52 · a* +13…+16 · b* +20…+24 | **ΔE 15–18** | Sáng và **vàng vọt** (mục tiêu b* +5,6, tính ra +20…+24) |')
A(u'')
A(u'⇒ **AGY ghi “ΔE < 1,0, mắt thường không phân biệt” — số đó KHÔNG khớp với dữ liệu ô in trong CSDL B.** '
  u'Nguyên nhân chính: `Nâu BS1008` (b* +52,8) và `Vàng YB 87` / `Vàng Y57` (b* +65…+78) kéo trục vàng lên quá mạnh, '
  u'còn lượng đỏ lại quá nhiều so với mục tiêu.')
A(u'')
A(u'⚠️ Giới hạn của phép kiểm chứng: số màu trong CSDL B là **ô in đã dán trên giấy** (nhuộm thấy màu đặc), còn khi lau màu lên gỗ '
  u'thì **phần lớn màu bị lau bớt**; dye lại cho màu khác pigment ở cùng tên ô. Vì vậy kết luận đúng phải là: '
  u'**hướng chọn mã thì hợp lý, nhưng tỉ lệ thì phải chỉnh và phải thử trên gỗ.**')
A(u'')
A(u'## 4. Tỉ lệ đã hiệu chỉnh — giữ đúng bộ mã AGY chọn, em tính lại tỉ lệ')
A(u'')
A(u'| Bộ mã (như AGY) | Tỉ lệ đề nghị | Nồng độ trong dung dịch | Màu dự kiến | ΔE |')
A(u'|---|---|---|---|---|')
for ten, v in HC['ket_qua'].items():
    tp = ' + '.join('%s **[%d%%]**' % (x['ten'], round(x['ti_le'] * 100)) for x in v['thanh_phan'])
    A(u'| %s | %s | ~5–6%% | %s | **%.2f** |' % (ten.split('(')[0].strip(), tp, v['hex_du_kien'], v['dE']))
A(u'')
A(u'## 5. Phương án tìm hoàn toàn bằng code (để anh có thêm lựa chọn)')
A(u'')
A(u'Em quét toàn bộ 121 ô bảng in, chỉ giữ các màu **nối được về mã có tồn kho**, tìm tổ hợp gần màu mẫu nhất:')
A(u'')
A(u'| # | Thành phần | Tỉ lệ | Màu dự kiến | ΔE |')
A(u'|---|---|---|---|---|')
seen, n = set(), 0
for k in TK['ket_qua']:
    key = tuple(sorted(x['ten'] for x in k['thanh_phan']))
    if key in seen:
        continue
    seen.add(key)
    n += 1
    A(u'| %d | %s | %s | %s | **%.2f** |' % (n, ' + '.join('%s **[%d%%]**' % (x['ten'], round(x['ti_le'] * 100)) for x in k['thanh_phan']),
                                             '/'.join('%d%%' % round(x['ti_le'] * 100) for x in k['thanh_phan']), k['hex_du_kien'], k['dE']))
    if n >= 4:
        break
A(u'')
A(u'Lưu ý: tổ hợp này nghiêng về **đỏ F3RK** (`Novoperm Red F3RK 70-CN09`) — khác hẳn hướng AGY. '
  u'Ô đen dùng trong tính toán (`Đen BT M100S`) có **độ tin cậy thấp** trong bảng in nên phải xác nhận lại.')
A(u'')
A(u'## 6. Cách pha & cách thử (đề nghị làm ngay)')
A(u'')
A(u'1. **Pha 3 dung dịch mẹ** (theo ô in): `Nâu BS1008 5%` · `Đỏ VM334 5%` · `Đỏ RS718 10%` + các mã bù còn lại; mỗi mẻ lấy mốc 100 g cho dễ tính.')
A(u'2. **Làm 4 ô thử trên cùng loại gỗ mộc**, nhuộm–lau đúng như mô tả: PA1 (AGY) · PA1 hiệu chỉnh tỉ lệ · PA2 hiệu chỉnh tỉ lệ · PA tìm bằng code. Ghi nhãn từng ô.')
A(u'3. **Chụp + đo lại 4 ô bằng code** (cùng khoảng cách, cùng ánh sáng) rồi so mục tiêu **L* %.1f / a* %+.1f / b* %+.1f**.' % (DO['mau']['L'], DO['mau']['a'], DO['mau']['b']))
A(u'4. **Chỉnh theo hướng lệch:** quá vàng (b* cao) → giảm/ngưng `Vàng Y57` hoặc `Vàng YB 87`; quá đỏ → giảm `Đỏ VM334`/`Đỏ RS718`; '
  u'quá sáng → tăng `MH Black 20` / `Đen BT M100S`; mất vân → giảm paste nâu, tăng tỉ lệ dye, lau kỹ hơn.')
A(u'5. Khi ô thử đạt ⇒ ghi **mã + tỉ lệ + nồng độ + số lớp** thành công thức chính thức cho lô.')
A(u'')
A(u'## 7. Điểm cần xác nhận')
A(u'')
A(u'- `MH Black 20 (BLACK 20)` và `Vàng Y57 (Y82)` **không có ô trên bảng in** ⇒ chưa có số màu; cần đo mẫu thật hoặc thay bằng mã đã đo.')
A(u'- Liên kết “tên trên bảng in ↔ mã tồn kho” (`Đỏ F3RK`↔CN09 · `Đỏ RB 97`↔RB 4097/RB-4097 · `Nâu BS1008`↔TB 1008/SP 1008 W · `Đen BT M100S`↔MA 100) mới là **suy đoán theo tên** — đề nghị kho xác nhận.')
A(u'- CSDL B **chưa có dữ liệu dung môi/chất kết nối** cho từng mã ⇒ phần dung môi trong 2 PA của AGY là đề xuất chung (NC/alkyd + butyl acetate/xylene/IPA/BCS), cần chốt theo hệ sơn thực tế.')
A(u'- Số màu lấy từ **ảnh chụp bảng in**, không phải đo quang phổ ⇒ phải làm ô thử mới chốt được.')
A(u'')
A(u'---')
A(u'')
A(u'## PHỤ LỤC — nguyên văn 2 phương án của AGY (mục D)')
A(u'')
A(doc_dau(agy)[:9000])
A(u'')

md = os.path.join(D, 'DE_XUAT_CONG_THUC_MAU_NEN_%s.md' % datetime.now().strftime('%d-%m-%Y'))
txt = '\r\n'.join(L) + '\r\n'
# md2docx chỉ nhận dòng phân cách bảng dạng "| :--- | ... |" ⇒ chuẩn hoá mọi dòng "|---|---|"
out = []
for line in txt.split('\r\n'):
    s = line.strip()
    if s.startswith('|') and set(s) <= set('|-: '):
        n = s.count('|') - 1
        out.append('| ' + ' | '.join([':---'] * n) + ' |')
    else:
        out.append(line)
txt = '\r\n'.join(out)
io.open(md, 'w', encoding='utf-8', newline='').write(txt)
print('đã ghi:', md, os.path.getsize(md), 'byte ·', len(L), 'dòng')
print('AGY đã có mục D:', bool(doc_dau(agy)[:50]))
