"""AutoPOE2 - Multi-Threaded WinRT OCR Stress Test (Rule 5 Authentic Data Protocol)
Phân hệ: Sư đoàn 2: Lead Perception Architect / Trung đoàn 1: OCR Runtime Stabilizer
Bối cảnh: Năm 2026 (Python 3.11, WinRT OCR, Windows Storage Streams).

Kiểm chứng cổng nghiệm thu (Merge Gate):
- Gọi 50 lần liên tiếp winocr.recognize_pil_sync trên các luồng khác nhau.
- Đạt 100% SUCCESS, 0 CRASH (Access Violation 0xc0000005).
- Sử dụng ảnh chụp màn hình game thật trong thư mục captures/.
"""

import os
import sys

# Reconfigure stdout/stderr to UTF-8
if hasattr(sys.stdout, "reconfigure"):
    try:
        sys.stdout.reconfigure(encoding="utf-8")
        sys.stderr.reconfigure(encoding="utf-8")
    except Exception:
        pass

# Đảm bảo root workspace có trong sys.path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

import time
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
from PIL import Image

import winocr
from src.common.vision_ocr import safe_recognize_pil_sync


def get_authentic_test_image() -> Image.Image:
    """Tải ảnh thật từ captures/ để tuân thủ Rule 5."""
    candidates = [
        "captures/reconnect/RECONNECT_STEP4_IN_GAME.png",
        "captures/20260910_054356_319_PERIODIC_ANALYSIS.png",
        "captures/debug_full_modal_ref.png",
        "captures/death_modal_crop.png",
    ]
    for path in candidates:
        if os.path.exists(path):
            try:
                img = Image.open(path).convert("RGBA")
                print(f"[AUTHENTIC DATA] Sử dụng ảnh capture thật: {path} (size={img.size})")
                return img
            except Exception:
                pass

    print("[WARN] Không tìm thấy ảnh trong danh sách ưu tiên, tìm ảnh PNG đầu tiên trong captures/...")
    captures_dir = "captures"
    if os.path.exists(captures_dir):
        for root, _, files in os.walk(captures_dir):
            for f in files:
                if f.lower().endswith(".png"):
                    p = os.path.join(root, f)
                    try:
                        img = Image.open(p).convert("RGBA")
                        print(f"[AUTHENTIC DATA] Sử dụng capture: {p} (size={img.size})")
                        return img
                    except Exception:
                        continue

    raise FileNotFoundError("Không tìm thấy ảnh capture thật nào trong thư mục captures/ (Vi phạm Rule 5)!")


def stress_test_winocr_direct(test_img: Image.Image, total_calls: int = 50, max_workers: int = 10):
    """Kiểm tra gọi trực tiếp winocr.recognize_pil_sync trên 50 luồng đồng thời."""
    print(f"\n========================================================")
    print(f"[STRESS TEST 1] winocr.recognize_pil_sync ({total_calls} calls, {max_workers} worker threads)")
    print(f"========================================================")

    # Crop một vùng nhỏ (HUD / UI banner) từ ảnh thật để mô phỏng tải thực tế
    w, h = test_img.size
    crop_img = test_img.crop((int(w * 0.1), int(h * 0.1), int(w * 0.5), int(h * 0.3)))

    errors = []
    success_count = 0
    lock = threading.Lock()
    t_start = time.perf_counter()

    def worker_task(call_id: int):
        thread_name = threading.current_thread().name
        thread_id = threading.get_ident()
        t0 = time.perf_counter()
        try:
            res = winocr.recognize_pil_sync(crop_img, lang="en")
            t_el = (time.perf_counter() - t0) * 1000.0
            assert isinstance(res, dict), f"Kết quả không phải dict: {type(res)}"
            assert "lines" in res, "Thiếu trường 'lines' trong OCR result"
            line_count = len(res.get("lines", []))
            with lock:
                nonlocal success_count
                success_count += 1
            return call_id, thread_id, thread_name, line_count, t_el
        except Exception as exc:
            with lock:
                errors.append((call_id, thread_id, thread_name, str(exc)))
            return call_id, thread_id, thread_name, -1, 0.0

    futures = []
    with ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="WinOCRStress") as executor:
        for i in range(total_calls):
            futures.append(executor.submit(worker_task, i + 1))

        for f in as_completed(futures):
            cid, tid, tname, lines, tel = f.result()
            if lines >= 0:
                print(f"  [PASS] Call #{cid:02d} | Thread: {tname} (ID: {tid}) | Lines: {lines} | Latency: {tel:.1f}ms")
            else:
                print(f"  [FAIL] Call #{cid:02d} | Thread: {tname} (ID: {tid}) | Error encountered!")

    total_time = time.perf_counter() - t_start
    print(f"--------------------------------------------------------")
    print(f"Kết quả Test 1: {success_count}/{total_calls} SUCCESS ({(success_count/total_calls)*100:.1f}%)")
    print(f"Lỗi: {len(errors)} | Tổng thời gian: {total_time:.2f}s | Tốc độ: {total_calls/total_time:.1f} calls/s")

    if errors:
        for err in errors:
            print(f"  -> Lỗi chi tiết: Call #{err[0]} (Thread {err[2]}): {err[3]}")
        return False
    return True


def stress_test_safe_recognize_wrapper(test_img: Image.Image, total_calls: int = 50, max_workers: int = 10):
    """Kiểm tra gọi qua wrapper an toàn safe_recognize_pil_sync trên 50 luồng đồng thời."""
    print(f"\n========================================================")
    print(f"[STRESS TEST 2] safe_recognize_pil_sync ({total_calls} calls, {max_workers} worker threads)")
    print(f"========================================================")

    w, h = test_img.size
    crop_img = test_img.crop((int(w * 0.4), int(h * 0.4), int(w * 0.8), int(h * 0.6)))

    errors = []
    success_count = 0
    lock = threading.Lock()
    t_start = time.perf_counter()

    def worker_task(call_id: int):
        thread_name = threading.current_thread().name
        thread_id = threading.get_ident()
        t0 = time.perf_counter()
        try:
            res = safe_recognize_pil_sync(crop_img, lang="en")
            t_el = (time.perf_counter() - t0) * 1000.0
            assert isinstance(res, dict), f"Kết quả không phải dict: {type(res)}"
            assert "lines" in res, "Thiếu trường 'lines' trong OCR result"
            line_count = len(res.get("lines", []))
            with lock:
                nonlocal success_count
                success_count += 1
            return call_id, thread_id, thread_name, line_count, t_el
        except Exception as exc:
            with lock:
                errors.append((call_id, thread_id, thread_name, str(exc)))
            return call_id, thread_id, thread_name, -1, 0.0

    futures = []
    with ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="SafeOCRStress") as executor:
        for i in range(total_calls):
            futures.append(executor.submit(worker_task, i + 1))

        for f in as_completed(futures):
            cid, tid, tname, lines, tel = f.result()
            if lines >= 0:
                print(f"  [PASS] Call #{cid:02d} | Thread: {tname} (ID: {tid}) | Lines: {lines} | Latency: {tel:.1f}ms")
            else:
                print(f"  [FAIL] Call #{cid:02d} | Thread: {tname} (ID: {tid}) | Error encountered!")

    total_time = time.perf_counter() - t_start
    print(f"--------------------------------------------------------")
    print(f"Kết quả Test 2: {success_count}/{total_calls} SUCCESS ({(success_count/total_calls)*100:.1f}%)")
    print(f"Lỗi: {len(errors)} | Tổng thời gian: {total_time:.2f}s | Tốc độ: {total_calls/total_time:.1f} calls/s")

    if errors:
        for err in errors:
            print(f"  -> Lỗi chi tiết: Call #{err[0]} (Thread {err[2]}): {err[3]}")
        return False
    return True


def main():
    print("================================================================")
    print("AutoPOE2 - WinRT OCR Multi-Threaded Stress Test Suite")
    print("Sư đoàn 2: Lead Perception Architect / OCR Runtime Stabilizer")
    print("================================================================")

    img = get_authentic_test_image()

    # Chạy Stress Test 1: winocr.recognize_pil_sync trực tiếp (50 lần, đa luồng)
    ok1 = stress_test_winocr_direct(img, total_calls=50, max_workers=10)

    # Chạy Stress Test 2: safe_recognize_pil_sync (50 lần, đa luồng)
    ok2 = stress_test_safe_recognize_wrapper(img, total_calls=50, max_workers=10)

    if ok1 and ok2:
        print("\n[MERGE GATE PASSED] 100/100 calls SUCCESS (100%), 0 CRASH, 0 Access Violation!")
        sys.exit(0)
    else:
        print("\n[MERGE GATE FAILED] Phát hiện lỗi trong quá trình thực thi đa luồng!")
        sys.exit(1)


if __name__ == "__main__":
    main()
