# -*- coding: utf-8 -*-
"""B33: mở Zalo -> hội thoại 'Trí QC' -> bóc NGUYÊN VĂN tin nhắn + kiểm kê ẢNH/FILE (kèm id để tải).
Lưu raw JSON. Chạy nền."""
import json, os, re, subprocess, time

S = 'tri1010'
LOG = open(r'C:\Claw 2\QC\_log_zalo_tri_1010.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')[-200:])
time.sleep(16)
log('trạng thái:', ev("JSON.stringify({t:document.title, co:!!document.querySelector('#contact-search-input')})")[-160:])

log(ev("(() => {const s=document.querySelector('#contact-search-input'); if(!s) return 'khong co o tim'; s.focus(); document.execCommand('selectAll',false,null); document.execCommand('insertText',false,'Tri QC'); return 'da go';})()")[-80:])
time.sleep(4)
log('kết quả tìm:', ev("(()=>{const a=[...document.querySelectorAll('.conv-item')].map(e=>e.innerText.split('\\n')[0]); return JSON.stringify(a.slice(0,8));})()")[-300:])
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';})()")[-80:])
time.sleep(5)
log('header:', ev("(document.querySelector('.header-title')||{}).innerText||'?'")[-120:])

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 'cuon';})()")
    time.sleep(2)

# bóc khối + id ảnh + file (KHÔNG lọc theo kích thước — luật 06/10)
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||''));
    const anh=imgs.map(x=>({id:(x.id||'').slice(0,26), w:x.naturalWidth, h:x.naturalHeight}));
    const files=[...b.querySelectorAll('.file-message__container')].map(f=>({ten:(f.innerText||'').split('\\n')[0].slice(0,60)}));
    return {i:i, cls:b.className, dai:t.length, text:t, so_anh:anh.length, anh:anh, so_file:files.length, file:files};
  }).filter(x=>x.dai>0||x.so_anh||x.so_file);
  return JSON.stringify({tong_khoi:blocks.length, ds:out.slice(-30)});
})()"""
raw = ev(js)
p = r'C:\Claw 2\QC\_raw_zalo_tri_1010.json'
try:
    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 .chat-message:', j['tong_khoi'], '| khối có nội dung:', len(j['ds']))
    for x in j['ds']:
        me = 'ME' if re.search(r'\bme\b', x['cls']) else '  '
        log('  #%-3s [%s] dài=%-4s ảnh=%-2s file=%-2s | %s' % (x['i'], me, x['dai'], x['so_anh'], x['so_file'], x['text'][:170].replace('\n', ' ⏎ ')))
        for a in x['anh']:
            log('        ảnh id=%s %sx%s' % (a['id'], a['w'], a['h']))
        for f in x['file']:
            log('        file: %s' % f['ten'])
except Exception as e:
    log('LỖI parse:', e, raw[:400])
log('đã lưu raw:', p)
LOG.close()
