# -*- coding: utf-8 -*-
"""Ghép NHÃN (AGY đọc) ↔ MÀU ĐO ĐƯỢC (dò ô màu) cho 11 bảng màu mausac.ngoducminh.com.
- Nhãn: parse `- `1-1` | `Vàng BT (5%)` | tông` trong _agy_bang_mau_web.md
- Màu: dò ô với nhiều mức erode, lọc ô rác theo diện tích, chọn bộ có số ô = số ô CÓ MÀU (không kể ô trống)
- Kiểm tra quy luật: cùng mã, 5% → 10% → 30% phải đậm dần (L* giảm)
- Xuất _bang_mau_web_final.csv
"""
import csv, io, os, re, sys
import numpy as np
sys.path.insert(0, r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze')
from _do_o_mau_v4 import do_o

DIR = r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze\trang-mausac'
IMGDIR = os.path.join(DIR, 'images')
MD = os.path.join(DIR, '_agy_bang_mau_web.md')
OUT = os.path.join(DIR, '_bang_mau_web_final.csv')
TRONG = '(không có nhãn)'


def doc_nhan(md_path):
    txt = io.open(md_path, encoding='utf-8', errors='replace').read()
    # tách theo tiêu đề ảnh: dòng bắt đầu bằng '## '
    blocks = re.split(r'\n##\s+\d+\.\s+', txt)
    res = {}
    for blk in blocks[1:]:
        name_m = re.search(r'([\w\-]+\.jpg)', blk)
        if not name_m:
            continue
        name = name_m.group(1)
        labels = []
        for line in blk.split('\n'):
            if '|' not in line:
                continue
            m = re.search(r'(\d+)\s*[-–]\s*(\d+)\s*[`*]*\s*\|\s*(.*)$', line)
            if not m:
                continue
            hang, cot, rest = int(m.group(1)), int(m.group(2)), m.group(3)
            cells = [c.replace('`', '').strip() for c in rest.split('|')]
            labels.append({'hang': hang, 'cot': cot, 'nhan': cells[0] if cells else '',
                           'tong': cells[1] if len(cells) > 1 else ''})
        if labels:
            # bỏ trùng lặp (nếu AGY nhắc lại ô trong phần ghi chú)
            seen, uniq = set(), []
            for lb in labels:
                k = (lb['hang'], lb['cot'])
                if k in seen:
                    continue
                seen.add(k); uniq.append(lb)
            if len(uniq) > len(res.get(name, [])):
                res[name] = uniq
    return res


def tach(ma_nhan):
    s = ma_nhan.replace('*', '').strip()
    m = re.search(r'\(\s*(\d+)\s*%\s*\)', s)
    nd = int(m.group(1)) if m else None
    ma = re.sub(r'\(\s*\d+\s*%\s*\)', '', s).strip(' -–·')
    return ma, nd


def loc_o(cells):
    """Bỏ ô rác: nhỏ hơn 35% diện tích trung vị."""
    if not cells:
        return cells
    areas = np.array([c['w'] * c['h'] for c in cells])
    med = float(np.median(areas))
    return [c for c in cells if c['w'] * c['h'] >= 0.35 * med]


MUC = [0.030, 0.035, 0.025, 0.040, 0.020, 0.045, 0.050, 0.015]


def main():
    nhan = doc_nhan(MD)
    if not nhan:
        print('⛔ không parse được nhãn nào'); return
    print('ảnh đọc được:', len(nhan), '| tổng nhãn:', sum(len(v) for v in nhan.values()))
    rows_out, tong_khop, tong_lech = [], 0, 0
    for name in sorted(nhan):
        p = os.path.join(IMGDIR, name)
        lb_all = nhan[name]
        lb_mau = [l for l in lb_all if l['nhan'].strip() != TRONG and l['nhan'].strip() != '']
        n_real = len(lb_mau)
        best, best_delta = None, 10 ** 9
        for ef in MUC:
            cs = loc_o(do_o(p, verbose=False, erode_frac=ef)) if os.path.exists(p) else []
            d = abs(len(cs) - n_real)
            if d < best_delta:
                best, best_delta = (ef, cs), d
            if d == 0:
                break
        ef, cells = best if best else (None, [])
        khop = len(cells) == n_real
        nhom = 'DYE' if 'dye' in name else ('PIGMENT' if 'pigment' in name else 'TỔNG')
        print('%-38s ô có màu %2d | dò %2d (erode %s) → %s' %
              (name, n_real, len(cells), ef, 'KHỚP' if khop else 'LỆCH %+d' % (len(cells) - n_real)))
        if khop:
            tong_khop += 1
        else:
            tong_lech += 1
        for i, lb in enumerate(lb_mau):
            ma, nd = tach(lb['nhan'])
            r = {'nhom': nhom, 'file': name, 'o': '%d-%d' % (lb['hang'], lb['cot']), 'nhan': lb['nhan'],
                 'ma_mau': ma, 'nong_do': nd if nd is not None else '', 'tong_mau': lb['tong'],
                 'hex': '', 'R': '', 'G': '', 'B': '', 'L': '', 'a': '', 'b': '', 'do_duoc': 'khong'}
            if khop:
                c = cells[i]
                r.update({'hex': c['hex'], 'R': c['R'], 'G': c['G'], 'B': c['B'], 'L': c['L'],
                          'a': c['a'], 'b': c['b'], 'do_duoc': 'co'})
            rows_out.append(r)
    # kiểm tra 5→10→30% đậm dần
    print('\n=== Kiểm tra cùng mã: 5% → 10% → 30% phải ĐẬM DẦN (L* giảm) ===')
    grp = {}
    for r in rows_out:
        if r['do_duoc'] == 'co' and r['nong_do'] != '':
            grp.setdefault((r['nhom'], r['file'], r['ma_mau']), {})[r['nong_do']] = float(r['L'])
    ngrp = nguoc = 0
    for k, v in grp.items():
        nds = sorted(v)
        if len(nds) >= 2:
            ngrp += 1
            Ls = [v[n] for n in nds]
            if not all(Ls[i] > Ls[i + 1] for i in range(len(Ls) - 1)):
                nguoc += 1
                print('   ⚠ %s | %s: L* = %s' % (k[2], nds, Ls))
    print('nhóm kiểm tra:', ngrp, '| ngược quy luật:', nguoc)
    print('\nảnh khớp số ô:', tong_khop, '| lệch:', tong_lech)
    with io.open(OUT, 'w', encoding='utf-8-sig', newline='') as f:
        w = csv.DictWriter(f, fieldnames=['nhom', 'file', 'o', 'nhan', 'ma_mau', 'nong_do', 'tong_mau',
                                          'hex', 'R', 'G', 'B', 'L', 'a', 'b', 'do_duoc'])
        w.writeheader(); w.writerows(rows_out)
    print('→', OUT, '|', len(rows_out), 'dòng | đo được màu:',
          sum(1 for r in rows_out if r['do_duoc'] == 'co'))


if __name__ == '__main__':
    main()
