# -*- coding: utf-8 -*-
r"""B189c: go CSDL C khoi dashboard — ban AN TOAN: compile() trong bo nho TRUOC khi ghi.
Neu compile loi -> KHONG ghi, in dong loi."""
import io, os, re, shutil, subprocess, sys, datetime, ast

GOC = r'C:\Claw 2\Nghien cuu\Dashboard-CSDL'
TS = datetime.datetime.now().strftime('%Y%m%d_%H%M')


def nap(f):
    return io.open(os.path.join(GOC, f), encoding='utf-8').read()


def ghi_an_toan(f, t):
    try:
        ast.parse(t)
    except SyntaxError as e:
        print('     !!! CU PHAP LOI sau khi sua: %s (dong %s)' % (e.msg, e.lineno))
        if e.lineno:
            for i, l in enumerate(t.split('\n')[max(0, e.lineno - 4):e.lineno + 1], max(1, e.lineno - 3)):
                print('        %4d| %s' % (i, l[:110]))
        raise SystemExit('DUNG LAI — KHONG GHI de giu file nguyen ven')
    p = os.path.join(GOC, f)
    io.open(p + '.tmp_ghi', 'w', encoding='utf-8', newline='').write(t)
    os.replace(p + '.tmp_ghi', p)


def xoa_dong(t, chuoi, mong, nhan=''):
    ra, n = [], 0
    for l in t.split('\n'):
        if chuoi in l:
            n += 1
            print('     - [%s] %s' % (nhan, l.strip()[:100]))
        else:
            ra.append(l)
    assert n == mong, 'xoa_dong %r: khop %d (mong %d)' % (chuoi[:50], n, mong)
    return '\n'.join(ra)


def xoa_doan(t, dau, cuoi, nhan=''):
    i = t.find(dau)
    assert i > 0, 'khong thay dau %r' % dau[:60]
    j = t.find(cuoi, i)
    assert j > 0, 'khong thay cuoi %r' % cuoi[:60]
    j = t.find('\n', j) + 1
    i = t.rfind('\n', 0, i) + 1
    print('     - [%s] %d dong (%s ... %s)' % (nhan, t[i:j].count('\n'), dau[:38], cuoi[:38]))
    return t[:i] + t[j:]


t = nap('tab_api.py')
shutil.copy2(os.path.join(GOC, 'tab_api.py'), os.path.join(GOC, '_tab_api_TRUOC_GO_%s.bak' % TS))
n0 = len(t)
print('  === tab_api.py (dry-run):')
t = xoa_dong(t, "'csdlc': os.environ.get('DASH_DB_CSDLC')", 1, 'DB map')
t = xoa_dong(t, "c = mo('csdlc')", 3, 'ket noi')
t = xoa_dong(t, "'Khách hàng (CSDL C)')", 1, 'KPI tong quan')
t = xoa_dong(t, "'Khách nhóm A (CSDL C)')", 1, 'KPI nhom A')
t = xoa_dong(t, "'Bài học kinh nghiệm (CSDL C)')", 1, 'KPI bai hoc')
t = t.replace("'btchem.db · CSDLC.db · CSDLA.db'", "'btchem.db · CSDLA.db'")
t = t.replace(", ghép CSDLC.khach_hang)", ")")
t = t.replace(") · CSDLC.db (khach_hang, lich_su_mua_hang)'", ")'")
t = t.replace("'btchem.db (su_co_kph) · CSDLC.db (kinh_nghiem)'", "'btchem.db (su_co_kph)'")
assert t.count('b.close(); c.close()') == 2
t = t.replace('; c.close()', '')                      # giu nguyen thut le dong
t = xoa_doan(t, '# kg theo nhóm / loại khách (ghép CSDLC theo tên chuẩn hoá)',
             "tieu_de='Cơ cấu Kg theo loại khách', kieu='pie'))", 'khoi nhom/loai khach')
# bang Top khach hang (CSDL C): lui ve dong 'hang = [' va cat toi het dong the.append(bang([...]))
k = t.find('doc(c, """select ten, tong_kg_2026')
assert k > 0, 'khong thay bang top khach CSDL C'
i = t.rfind('hang = [', 0, k)
j = t.find('Top khách hàng theo sản lượng năm 2026 (CSDL C)', k)
assert i > 0 and j > 0
j = t.find('\n', j) + 1
print('     - [bang top khach] %d dong' % t[i:j].count('\n'))
t = t[:i] + t[j:]
t = xoa_doan(t, '# bài học kinh nghiệm (CSDL C) theo tháng',
             "'don_vi': 'bài', 'ngang': False, 'mau': MAU[4]})", 'bieu do bai hoc')
t = xoa_doan(t, 'the.append(cot_ngang(doc(c, """select coalesce(nullif(trim(chu_de)',
             "'bài', 15, 'Chủ đề bài học kinh nghiệm nhiều nhất'))", 'bang chu de')
# dong danh sach KPI: dong cuoi truoc day ket thuc bang ',' -> doi thanh ']'
t = re.sub(r"(\n[ \t]*kpi\(so\((?:dem|so)\([^\n]*?\)\), '[^']*')\),\n", r"\1]\n", t, count=0) \
    if False else t
for cu, moi in (("'Thiếu ngày tạo'),\n", "'Thiếu ngày tạo')]\n"),
                ("'Tổng kg lũy kế'),\n", "'Tổng kg lũy kế')]\n")):
    if cu in t:
        t = t.replace(cu, moi)
        print('     - [dong danh sach KPI] %r -> dien "]"' % cu.strip())
assert "c = mo('csdlc')" not in t and 'CSDL C' not in t and 'CSDLC' not in t, 'van con nhac CSDL C'
# chuan hoa thut le dong dong ket noi (phai ngang cap ham = 4 space)
t = re.sub(r"\n[ \t]+b\.close\(\)", "\n    b.close()", t)
ghi_an_toan('tab_api.py', t)
print('  tab_api.py: %d -> %d byte (giam %d) · cu phap OK' % (n0, len(t), n0 - len(t)))

s = nap('server_powerbi.py')
shutil.copy2(os.path.join(GOC, 'server_powerbi.py'), os.path.join(GOC, '_server_powerbi_TRUOC_GO_%s.bak' % TS))
n1 = len(s)
print('\n  === server_powerbi.py (dry-run):')
s = xoa_dong(s, "'csdlc': os.environ.get('DASH_DB_CSDLC')", 1, 'DB map')
s = xoa_dong(s, "'csdlc': [('khach_hang', 'count(*)')", 1, 'nhip dau')
s = xoa_dong(s, "('lich_su_mua_hang', 'count(*)')],", 1, 'nhip cuoi')
s = xoa_dong(s, "cl = sqlite3.connect('file:%s?mode=ro' % DB['csdlc']", 1, 'ket noi')
s = xoa_dong(s, "'khach_hang': dem(cl, 'select count(*) from khach_hang')", 1, 'KPI khach')
s = xoa_dong(s, "'kinh_nghiem': dem(cl, 'select count(*) from kinh_nghiem')", 1, 'KPI bai hoc')
s = re.sub(r"\n[ \t]*cl\.close\(\)", '', s)
assert 'csdlc' not in s.lower() and 'CSDLC' not in s
ghi_an_toan('server_powerbi.py', s)
print('  server_powerbi.py: %d -> %d byte (giam %d) · cu phap OK' % (n1, len(s), n1 - len(s)))

print('\n  === KIEM CHUNG:')
for f in ('tab_api.py', 'server_powerbi.py'):
    r = subprocess.run([sys.executable, '-m', 'py_compile', os.path.join(GOC, f)], capture_output=True, text=True)
    t2 = nap(f)
    print('     %-20s py_compile=%s | con %d dong nhac CSDL C | %d dong' % (
        f, 'OK' if r.returncode == 0 else 'LOI', 
        len([l for l in t2.split('\n') if re.search(r'csdlc|CSDL C|kinh_nghiem', l, re.I)]), t2.count('\n') + 1))
