# -*- coding: utf-8 -*-
r"""B65: lấy 2 file còn thiếu của tuần 41 từ Zalo (Thu: KẾT QUẢ MẪU TUẦN 41.xlsx · Lan: W41.xlsx).
Cách: mở hội thoại -> cuộn tìm card file -> hover + bấm a.file-message__actions.download -> poll ~/Downloads.
Nếu không thấy trong hội thoại thì dùng ô tìm kiếm file toàn cục."""
import glob, hashlib, json, os, re, shutil, subprocess, time, zipfile

S = 'zalo41'
DL = os.path.join(os.path.expanduser('~'), 'Downloads')
DICH = r'C:\Claw 2\Bao cao - Hanh chinh\Bao cao lam mau'
LOG = open(r'C:\Claw 2\_log_zalo_lammau_T41.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=300):
    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)


def chup_dl():
    d = {}
    for p in glob.glob(os.path.join(DL, '*')):
        if os.path.isfile(p):
            d[p] = (os.path.getmtime(p), os.path.getsize(p))
    return d


def cho_file(truoc, ten_dich, giay=90):
    """poll ~/Downloads tới khi có file mới đủ lớn (xlsx hoặc .tmp)."""
    t0 = time.time()
    while time.time() - t0 < giay:
        time.sleep(4)
        for p, (mt, sz) in chup_dl().items():
            if p in truoc:
                continue
            if sz > 3000 and (p.lower().endswith(('.xlsx', '.xls')) or p.lower().endswith('.tmp') or '.tmp' in p.lower()):
                if time.time() - mt < 180:
                    return p, sz
    return None, 0


lst = ba('browser', 'list')
ID = re.search(r'id=(direct_local_\d+)', lst).group(1)
log('  browser id:', ID)
log(ba('--session', S, 'browser', 'open', ID, 'https://chat.zalo.me')[-120:])
time.sleep(16)
log('  trạng thái:', ev("JSON.stringify({t:document.title, co:!!document.querySelector('#contact-search-input')})")[-120:])

MUC = [('Thu VPKT', 'KẾT QUẢ MẪU TUẦN 41', r'KẾT QUẢ MẪU TUẦN 41.xlsx'),
       ('Ms Lan vpkt', 'W41', r'W41.xlsx')]

ket = []
for hoi_thoai, khop, ten_dich in MUC:
    log('')
    log('=== %s → tìm file khớp “%s”' % (hoi_thoai, khop))
    # mở hội thoại theo tên (regex, không phân biệt hoa/thường)
    ev("(() => {const s=document.querySelector('#contact-search-input'); if(!s) return 'x'; s.focus(); document.execCommand('selectAll',false,null); document.execCommand('insertText',false,'%s'); return 'ok';})()" % hoi_thoai.split()[0])
    time.sleep(4)
    r = ev("(() => {const els=[...document.querySelectorAll('.conv-item')]; const el=els.find(e=>new RegExp('%s','i').test(e.innerText||'')); if(!el) return 'KHONG THAY'; el.click(); return 'da bam';})()" % hoi_thoai.replace(' ', '.*'))
    log('  mở hội thoại:', r[-60:])
    time.sleep(5)
    log('  header:', ev("(document.querySelector('.header-title')||{}).innerText||'?'")[-60:])

    done = False
    for vong in range(1, 11):
        # cuộn vùng tin nhắn lên
        ev("(() => {const cs=[...document.querySelectorAll('div')].filter(d=>d.scrollHeight>d.clientHeight+40 && d.querySelector('.chat-message')); if(cs[0]){cs[0].scrollTop=Math.max(0,cs[0].scrollTop-cs[0].clientHeight*0.85);} return cs.length;})()")
        time.sleep(2.5)
        co = ev("(() => {const cs=[...document.querySelectorAll('.file-message__container')]; const hit=cs.filter(c=>new RegExp('%s','i').test((c.innerText||'')+' '+([...c.querySelectorAll('[title]')].map(x=>x.getAttribute('title')).join(' ')))); return JSON.stringify({tong:cs.length, khop:hit.length, ten:hit.map(h=>(h.innerText||'').split('\\n')[0].slice(0,50))});})()" % khop.replace('Ế', '.'))
        log('   vòng %-2s: %s' % (vong, co[-150:]))
        if '"khop":0' not in co and 'khop":0' not in co:
            truoc = chup_dl()
            r2 = ev("""(() => {const cs=[...document.querySelectorAll('.file-message__container')];
                        const hit=cs.filter(c=>new RegExp('%s','i').test((c.innerText||'')+' '+([...c.querySelectorAll('[title]')].map(x=>x.getAttribute('title')).join(' '))));
                        const card=hit[hit.length-1]; if(!card) return 'khong co card';
                        ['mouseover','mouseenter'].forEach(t=>card.dispatchEvent(new MouseEvent(t,{bubbles:true})));
                        const nut=card.querySelector('a.file-message__actions.download');
                        if(!nut) return 'khong co nut';
                        nut.click(); return 'da bam tai';})()""" % khop.replace('Ế', '.'))
            log('   bấm tải:', r2[-40:])
            if 'da bam' in r2:
                p, sz = cho_file(truoc, ten_dich, 120)
                if p:
                    dich = os.path.join(DICH, ten_dich)
                    if os.path.exists(dich):
                        same = hashlib.md5(open(p, 'rb').read()).hexdigest() == hashlib.md5(open(dich, 'rb').read()).hexdigest()
                        log('   file đích đã tồn tại — %s' % ('trùng md5, bỏ' if same else 'KHÁC nội dung'))
                        if not same:
                            shutil.copy2(p, os.path.join(DICH, ten_dich.replace('.xlsx', ' (2).xlsx')))
                            log('   đã lưu bản (2)')
                    else:
                        shutil.copy2(p, dich)
                        log('   đã lưu: %s (%d B) từ %s' % (ten_dich, os.path.getsize(dich), os.path.basename(p)))
                    ket.append((hoi_thoai, ten_dich, os.path.getsize(dich) if os.path.exists(dich) else 0))
                    done = True
                    break
        if vong == 10 and not done:
            log('   KHÔNG tìm thấy card trong hội thoại sau 10 vòng cuộn')

log('')
log('  === KẾT QUẢ ===')
for k in ket:
    print('   %s | %s | %d B' % k)
ba('session', 'close', S)
log('  đã đóng browser')
LOG.close()
