# -*- coding: utf-8 -*-
r"""B55: Zalo 'Loc QC ( So 2)' -> bóc khối tin + TẢI ẢNH của khối cuối (tin 16:36) bằng canvas->base64."""
import base64, hashlib, json, os, re, subprocess, time

S = 'loc1210'
DICH = r'C:\Claw 2\QC\images\_zalo_loc_1210'
os.makedirs(DICH, exist_ok=True)
LOG = open(r'C:\Claw 2\QC\_log_zalo_loc_1210.txt', 'a', encoding='utf-8')


def log(*a):
    s = ' '.join(str(x) for x in a); print(s, flush=True); LOG.write(s + '\n'); LOG.flush()


def ba(*args, timeout=240):
    try:
        r = subprocess.run(['browser-act'] + list(args), capture_output=True, text=True,
                           encoding='utf-8', errors='replace', timeout=timeout)
        return ((r.stdout or '') + (r.stderr or '')).strip()
    except subprocess.TimeoutExpired:
        return 'TIMEOUT'


def ev(js):
    return ba('--session', S, 'eval', js)


lst = ba('browser', 'list')
m = re.search(r'id=(direct_local_\d+)', lst)
ID = m.group(1) if m else None
log('browser id:', ID)
log(ba('--session', S, 'browser', 'open', ID, 'https://chat.zalo.me')[-160:])
time.sleep(16)
log('trạng thái:', ev("JSON.stringify({t:document.title, co:!!document.querySelector('#contact-search-input')})")[-140:])
ev("(() => {const s=document.querySelector('#contact-search-input'); if(!s) return 'x'; s.focus(); document.execCommand('selectAll',false,null); document.execCommand('insertText',false,'Loc QC'); return 'ok';})()")
time.sleep(4)
log('tìm thấy:', ev("(()=>{const a=[...document.querySelectorAll('.conv-item')].map(e=>e.innerText.split('\\n')[0]); return JSON.stringify(a.slice(0,6));})()")[-260:])
log(ev("(()=>{const d=document.querySelector('div[id^=friend-item-].conv-item')||document.querySelector('div[id^=friend-item-]'); if(!d) return 'khong thay'; d.click(); return 'da bam';})()")[-60:])
time.sleep(5)
log('header:', ev("(document.querySelector('.header-title')||{}).innerText||'?'")[-100:])
for i in range(5):
    ev("(()=>{const c=[...document.querySelectorAll('div,section,ul')].filter(e=>e.scrollHeight>e.clientHeight+200); c.sort((a,b)=>b.scrollHeight-a.scrollHeight); if(c[0]){c[0].scrollTop=c[0].scrollTop-1500;} return 1;})()")
    time.sleep(2)

js = """(() => {
  const blocks=[...document.querySelectorAll('.chat-message')];
  const out=blocks.map((b,i)=>{
    const t=(b.innerText||'').trim();
    const imgs=[...b.querySelectorAll('img.zimg-el')].filter(x=>/^blob:/.test(x.src||''));
    return {i:i, dai:t.length, text:t, so_anh:imgs.length,
            anh:imgs.map(x=>({id:(x.id||''), w:x.naturalWidth, h:x.naturalHeight}))};
  }).filter(x=>x.dai>0||x.so_anh);
  return JSON.stringify({tong:blocks.length, ds:out.slice(-14)});
})()"""
raw = ev(js)
p = r'C:\Claw 2\QC\_raw_zalo_loc_1210.json'
j = json.loads(raw[raw.index('{'):raw.rindex('}') + 1])
json.dump(j, open(p, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
log('tổng khối:', j['tong'], '| có nội dung:', len(j['ds']))
for x in j['ds']:
    log('  #%-3s ảnh=%-2s | %s' % (x['i'], x['so_anh'], x['text'][:200].replace('\n', ' ⏎ ')))
    for a in x['anh']:
        log('        ảnh id=%s %sx%s' % (a['id'], a['w'], a['h']))

# tải ảnh của khối CUỐI có ảnh
khoi = [x for x in j['ds'] if x['so_anh']]
if khoi:
    x = khoi[-1]
    log('')
    log('=== TẢI %d ẢNH của khối #%s (tin cuối) ===' % (x['so_anh'], x['i']))
    seen, n = {}, 0
    for a in x['anh']:
        id_ = a['id'].split('.')[0].replace('img-', '')
        r = ev("(() => {const l=[...document.querySelectorAll('img.zimg-el')]; const g=l.find(x=>(x.id||'').indexOf('%s')>=0); if(!g) return 'KHONG THAY'; g.scrollIntoView({block:'center'}); if(!g.naturalWidth) return 'CHUA LOAD'; const c=document.createElement('canvas'); c.width=g.naturalWidth; c.height=g.naturalHeight; c.getContext('2d').drawImage(g,0,0,c.width,c.height); try{window.__B64=c.toDataURL('image/jpeg',0.92);}catch(e){return 'LOI';} return 'OK '+g.naturalWidth+'x'+g.naturalHeight+' '+window.__B64.length;})()" % id_)
        log('  id %s: %s' % (id_, r[-40:]))
        if not r.startswith('OK'):
            continue
        tong = int(r.split()[-1]); phan, vt = [], 0
        while vt < tong:
            z = ev('String(window.__B64.slice(%d,%d))' % (vt, vt + 30000)).strip()
            if z.startswith('"') and z.endswith('"'):
                z = z[1:-1]
            phan.append(z); vt += 30000
        chuoi = ''.join(phan)
        if len(chuoi) < tong * 0.9:
            log('     -> THIẾU dữ liệu — bỏ'); continue
        th = base64.b64decode(chuoi.split(',', 1)[1])
        h = hashlib.md5(th).hexdigest()[:12]
        if h in seen:
            log('     -> TRÙNG md5 với %s' % seen[h]); continue
        n += 1
        ten = os.path.join(DICH, 'zalo_loc_1210_%02d.jpg' % n)
        open(ten, 'wb').write(th)
        seen[h] = os.path.basename(ten)
        from PIL import Image
        im = Image.open(ten)
        log('     -> %s  %d B  %sx%s  md5 %s' % (os.path.basename(ten), len(th), im.width, im.height, h))
    log('đã tải %d ảnh vào %s' % (n, DICH))
log('đã lưu raw:', p)
LOG.close()
