# -*- coding: utf-8 -*-
"""CHỐT (cuối): gán nhãn ↔ màu theo LƯỚI, đo màu bằng v5 (có cân trắng cục bộ).
- Mỗi hàng: giữ đúng số ô = số nhãn của hàng đó (chọn ô lớn nhất, sắp theo x)
- Ghi rõ phương pháp gán: 'khop' (số ô toàn bảng trùng) hay 'gan-vi-tri' (chọn theo hàng)
Xuất _bang_mau_web_chot.csv (dùng để nạp vào CSDL B).
"""
import csv, io, os, 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_v5 import do_o
from _ghep_nhan_va_mau import doc_nhan, tach

DIR = r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze\trang-mausac'
IMGDIR = os.path.join(DIR, 'images')
OUT = os.path.join(DIR, '_bang_mau_web_chot.csv')
TRONG = '(không có nhãn)'
MUC = [0.030, 0.025, 0.035, 0.020, 0.040, 0.045, 0.015, 0.050, 0.055, 0.060]


def loc(cells):
    if not cells:
        return []
    a = np.array([c['w'] * c['h'] for c in cells])
    med = float(np.median(a))
    return [c for c in cells if c['w'] * c['h'] >= 0.35 * med]


def kmeans1d(v, k, iters=80):
    v = np.asarray(v, dtype=float)
    if len(v) < k or k < 1:
        return None
    cent = np.quantile(v, np.linspace(0.02, 0.98, k))
    for _ in range(iters):
        idx = np.argmin(np.abs(v[:, None] - cent[None, :]), axis=1)
        new = np.array([v[idx == j].mean() if (idx == j).any() else cent[j] for j in range(k)])
        if np.allclose(new, cent):
            break
        cent = new
    return idx


def main():
    nhan = doc_nhan(os.path.join(DIR, '_agy_bang_mau_web.md'))
    final, bao_cao = [], []
    for name in sorted(nhan):
        lb = [l for l in nhan[name] if l['nhan'].strip() not in (TRONG, '')]
        if not lb:
            continue
        mong = {}
        for l in lb:
            mong.setdefault(l['hang'], []).append(l)
        so_hang = max(mong)
        p = os.path.join(IMGDIR, name)
        best = None
        for ef in MUC:
            cells = loc(do_o(p, erode_frac=ef))
            if best is None or abs(len(cells) - len(lb)) < abs(len(best[1]) - len(lb)):
                best = (ef, cells)
            if len(cells) == len(lb):
                break
        ef, cells = best
        idx = kmeans1d([c['y'] + c['h'] / 2.0 for c in cells], so_hang)
        rows_by_hang = {}
        if idx is not None:
            for c, j in zip(cells, idx):
                rows_by_hang.setdefault(j + 1, []).append(c)
        khop = (len(cells) == len(lb))
        ph = 'khop' if khop else 'gan-vi-tri'
        nhom = 'DYE' if 'dye' in name else ('PIGMENT' if 'pigment' in name else 'TỔNG')
        n_do = 0
        for h in sorted(mong):
            can = mong[h]
            row = sorted(rows_by_hang.get(h, []), key=lambda c: -c['w'] * c['h'])[:len(can)]
            row.sort(key=lambda c: c['x'])
            for i, l in enumerate(sorted(can, key=lambda x: x['cot'])):
                ma, nd = tach(l['nhan'])
                r = {'nhom': nhom, 'file': name, 'o': '%d-%d' % (l['hang'], l['cot']), 'nhan': l['nhan'],
                     'ma_mau': ma, 'nong_do': nd if nd is not None else '', 'tong_mau': l['tong'],
                     'hex': '', 'R': '', 'G': '', 'B': '', 'L': '', 'a': '', 'b': '', 'do_duoc': 'khong',
                     'cach_gan': ''}
                if i < len(row):
                    c = row[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', 'cach_gan': ph})
                    n_do += 1
                final.append(r)
        bao_cao.append((name, len(lb), len(cells), khop, n_do))
    print('%-38s %5s %4s %-9s %5s' % ('Ảnh', 'nhãn', 'ô', 'số ô', 'đo được'))
    for b in bao_cao:
        print('%-38s %5d %4d %-9s %5d' % (b[0], b[1], b[2], 'KHỚP' if b[3] else 'lệch', b[4]))
    do = sum(1 for r in final if r['do_duoc'] == 'co')
    print('\ntổng dòng:', len(final), '| dòng đo được màu:', do)
    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', 'cach_gan'])
        w.writeheader(); w.writerows(final)
    print('→', OUT)


if __name__ == '__main__':
    main()
