# -*- coding: utf-8 -*-
"""CHẠY AGY THEO 2 CHẾ ĐỘ trong DỰ ÁN A (dùng cho các lần chủ dự án gửi ảnh).

  python _run_agy_theo_lo.py cap_nhat   -> đọc ảnh trong anh_cap_nhat\\ -> GHI vào CSDLA (có backup)
  python _run_agy_theo_lo.py de_xuat    -> đọc ảnh trong anh_mau_moi\\  -> ĐỀ XUẤT quy trình (chỉ đọc CSDLA)
  python _run_agy_theo_lo.py            -> tự nhận: có ảnh ở anh_cap_nhat thì cập nhật, có ở anh_mau_moi thì đề xuất
"""
import hashlib, json, os, shutil, subprocess, sys, time

AGY = r"C:\Users\admin\AppData\Local\agy\bin\agy.exe"
DIR = r"C:\Claw 2\Nghien cuu\Du-an-A-Quy-trinh-son"
PROJECT = "2f54d0c6-f33f-4dae-b5b7-840339496ec7"
CACHE = os.path.join(os.environ['LOCALAPPDATA'], 'hermes', 'cache', 'images')
STATE = os.path.join(DIR, '_anh_da_xu_ly.json')          # md5 các ảnh đã từng được xử lý (tránh xử lý lại)
MARK = os.path.join(DIR, '_lan_chay_cuoi.txt')           # mốc thời gian: chỉ lấy ảnh MỚI HƠN lần chạy trước
EXT = ('.jpg', '.jpeg', '.png', '.webp')


def _doc_mark():
    """Mốc thời gian lần chạy trước (mặc định: 60 phút trước nếu chưa có)."""
    try:
        return float(open(MARK, encoding='utf-8').read().strip())
    except Exception:
        return time.time() - 3600


def _ghi_mark():
    open(MARK, 'w', encoding='utf-8').write('%.3f' % time.time())


def _doc_state():
    try:
        return json.load(open(STATE, encoding='utf-8'))
    except Exception:
        return {}


def _ghi_state(d):
    json.dump(d, open(STATE, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)


def thu_muc(mode):
    return os.path.join(DIR, 'anh_cap_nhat' if mode == 'cap_nhat' else 'anh_mau_moi')


def chup_anh_moi(mode):
    """Copy ảnh MỚI (chưa từng xử lý) từ cache Telegram vào thư mục nhận.

    Chống xử lý lại: mỗi ảnh được ghi nhận md5 vào _anh_da_xu_ly.json (kèm thư mục đích + thời điểm).
    """
    tm = thu_muc(mode)
    os.makedirs(tm, exist_ok=True)
    state = _doc_state()
    da_co = set(state.keys())
    mark = _doc_mark()
    bo_qua_cu = 0
    for f in os.listdir(tm):                              # ảnh đang nằm trong thư mục nhận
        if f.lower().endswith(EXT):
            da_co.add(hashlib.md5(open(os.path.join(tm, f), 'rb').read()).hexdigest())
    lo = [f for f in os.listdir(CACHE) if f.startswith('img_')]
    lo.sort(key=lambda f: os.path.getmtime(os.path.join(CACHE, f)))
    i = len([f for f in os.listdir(tm) if f.lower().endswith(EXT)])
    for f in lo:
        p = os.path.join(CACHE, f)
        if os.path.getmtime(p) <= mark:                   # ảnh cũ (đã có từ lần chạy trước) -> bỏ qua
            bo_qua_cu += 1
            continue
        h = hashlib.md5(open(p, 'rb').read()).hexdigest()
        if h in da_co:
            continue
        da_co.add(h)
        i += 1
        dst = os.path.join(tm, '%s_%02d.jpg' % ('capnhat' if mode == 'cap_nhat' else 'mau_moi', i))
        shutil.copy2(p, dst)
        state[h] = {'thu_muc': os.path.basename(dst), 'che_do': mode,
                    'thoi_diem': time.strftime('%Y-%m-%d %H:%M:%S'), 'tu_cache': f}
        print('   + %s  (%d byte, từ %s)' % (os.path.basename(dst), os.path.getsize(dst), f))
    _ghi_state(state)
    _ghi_mark()
    n = len([f for f in os.listdir(tm) if f.lower().endswith(EXT)])
    print('   ảnh trong %s: %d | bỏ qua %d ảnh cũ | đã theo dõi: %d'
          % (os.path.basename(tm), n, bo_qua_cu, len(state)))
    return n


def don_thu_muc(mode):
    """Chuyển ảnh của lần chạy TRƯỚC (đã xử lý) sang `da_xu_ly\\` để thư mục nhận chỉ còn lô mới."""
    tm, arch = thu_muc(mode), os.path.join(DIR, 'da_xu_ly')
    os.makedirs(arch, exist_ok=True)
    state = _doc_state()
    n = 0
    for f in os.listdir(tm):
        p = os.path.join(tm, f)
        if not (os.path.isfile(p) and f.lower().endswith(EXT)):
            continue
        h = hashlib.md5(open(p, 'rb').read()).hexdigest()
        if state.get(h, {}).get('da_xu_ly'):
            shutil.move(p, os.path.join(arch, f))
            n += 1
    if n:
        _ghi_state(state)
        print('   lưu trữ %d ảnh đã xử lý -> da_xu_ly\\' % n)
    return n


def danh_dau_da_xu_ly(mode):
    """Sau khi agy chạy xong: đánh dấu ảnh trong thư mục nhận là đã xử lý."""
    tm = thu_muc(mode)
    state = _doc_state()
    for f in os.listdir(tm):
        p = os.path.join(tm, f)
        if not (os.path.isfile(p) and f.lower().endswith(EXT)):
            continue
        h = hashlib.md5(open(p, 'rb').read()).hexdigest()
        state.setdefault(h, {'thu_muc': f, 'che_do': mode, 'thoi_diem': time.strftime('%Y-%m-%d %H:%M:%S')})
        state[h]['da_xu_ly'] = True
    _ghi_state(state)


def main():
    mode = sys.argv[1] if len(sys.argv) > 1 else None
    if mode not in ('cap_nhat', 'de_xuat'):
        n1 = chup_anh_moi('cap_nhat')
        n2 = chup_anh_moi('de_xuat')
        mode = 'cap_nhat' if n1 else ('de_xuat' if n2 else 'cap_nhat')
    else:
        chup_anh_moi(mode)

    yeucau = os.path.join(DIR, 'YEU_CAU_cap_nhat_csdl.txt' if mode == 'cap_nhat' else 'YEU_CAU_de_xuat_quy_trinh.txt')
    log = os.path.join(DIR, '_log_agy_cap_nhat.txt' if mode == 'cap_nhat' else '_log_agy_de_xuat.txt')
    sub = 'anh_cap_nhat' if mode == 'cap_nhat' else 'anh_mau_moi'
    don_thu_muc(mode)                                     # dọn lô trước -> thư mục chỉ còn lô mới
    them = ('Write to CSDLA.db with sqlite3 as instructed (BACKUP THE DB FIRST).' if mode == 'cap_nhat'
            else 'CSDLA.db is READ ONLY - do not write to it.')
    prompt = ('Read the instruction file "%s" (UTF-8, Vietnamese) and follow it exactly. '
              'The images to analyse are in the subfolder "%s". %s '
              'Use the current project folder "%s" as working directory; write every output file with real file-write tools.'
              % (yeucau, sub, them, DIR))
    cmd = [AGY, '-p', prompt, '--model', 'gemini-3.8-flash-high', '--project', PROJECT,
           '--add-dir', DIR, '--dangerously-skip-permissions', '--output-format', 'json', '--print-timeout', '0']
    print('CHẾ ĐỘ: %s | yêu cầu: %s' % (mode, os.path.basename(yeucau)))
    t0 = time.time()
    p = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', cwd=DIR)
    dt = time.time() - t0
    with open(log, 'w', encoding='utf-8') as f:
        f.write('BẮT ĐẦU %s | chế độ %s\n=== ELAPSED %.1f s | RC %s ===\n' % (time.strftime('%H:%M:%S'), mode, dt, p.returncode))
        f.write((p.stdout or '') + '\n' + (p.stderr or '')[-2000:] + '\nKẾT THÚC %s\n' % time.strftime('%H:%M:%S'))
    print('xong %.1f s | rc=%s' % (dt, p.returncode))
    if p.returncode == 0:
        danh_dau_da_xu_ly(mode)
        print('   đã đánh dấu lô ảnh này là đã xử lý (lần sau tự lưu trữ vào da_xu_ly\\)')
    try:
        j = json.loads(p.stdout)
        print('status:', j.get('status'), '| tokens:', (j.get('usage') or {}).get('total_tokens'))
        print('response:', (j.get('response') or '')[:1500].replace('\n', ' '))
    except Exception as e:
        print('không parse json:', e, '|', (p.stdout or '')[-1200:])
    print('--- file mới nhất trong dự án ---')
    for f in sorted(os.listdir(DIR), key=lambda x: os.path.getmtime(os.path.join(DIR, x)), reverse=True)[:10]:
        print('   %-50s %d' % (f, os.path.getsize(os.path.join(DIR, f))))


if __name__ == '__main__':
    main()
