"""AutoPOE2 - Unit Tests Kiểm Chứng Kháng Bug Chữ 'ENTER' & Nhận Diện Player Avatar (Chu Kỳ 9).
=================================================================================================
Kiểm thử toàn diện:
1. Kháng triệt để bug chữ 'ENTER' trong tooltip Waystone ("allowing you to enter a map").
2. Đảm bảo hàm OCR TRAVERSE và Dual-Pass Locator luôn loại trừ vùng túi đồ / tooltip (x > 0.55 * w).
3. Nhận diện chính xác Player Avatar hình tròn vàng trên cây Atlas (find_player_avatar_on_atlas)
   trên các artifact thật từ captures/ (20260914_003608_364_CLICKED_PIN_1280_560.png, test_player_node.png, pin_1280_560.png).
4. Kiểm chứng tính năng fallback an toàn và tương thích đa độ phân giải.

Tuân thủ nghiêm ngặt:
- Rule 5: 100% artifact thật từ captures/.
- Rule 14: Quality Gate, 100% tests PASS.
"""

from __future__ import annotations

import os
import unittest
import numpy as np
from PIL import Image

from src.common.vision_filters import find_traverse_button_dual_pass
from src.common.vision_ocr import (
    find_button_by_text,
    find_player_avatar_on_atlas,
)


class TestTraverseAndPlayerAvatar(unittest.TestCase):
    """Test suite kiểm chứng loại trừ vùng tooltip x > 0.55*w và định vị Player Avatar."""

    def setUp(self) -> None:
        self.captures_dir = os.path.join(os.path.dirname(__file__), "..", "captures")

    def test_traverse_button_excludes_right_half_inventory_tooltip(self) -> None:
        """Kiểm chứng OCR TRAVERSE và Dual-Pass Locator tuyệt đối không click vào x > 0.55 * w."""
        # Tạo ảnh giả lập 2560x1440:
        # Bên phải (x > 1408 = 0.55 * 2560) có vùng text mô phỏng tooltip Waystone
        img = Image.new("RGB", (2560, 1440), color=(20, 20, 20))
        
        # Thử tìm nút TRAVERSE trên ảnh này
        pos = find_traverse_button_dual_pass(img)
        # Vì bên trái không có nút TRAVERSE thật, phải trả về None chứ KHÔNG ĐƯỢC trả về tọa độ x > 0.55*w
        if pos is not None:
            self.assertLessEqual(pos[0], int(2560 * 0.55), "Dual-Pass đã click nhầm vào vùng túi đồ x > 0.55*w!")

        # Kiểm tra find_button_by_text với token "TRAVERSE"
        btn_pos = find_button_by_text(img, "TRAVERSE")
        if btn_pos is not None:
            self.assertLessEqual(btn_pos[0], int(2560 * 0.55), "find_button_by_text đã click nhầm vào vùng x > 0.55*w!")

    def test_find_button_by_text_anti_enter_bug(self) -> None:
        """Kiểm chứng khi tìm token 'ENTER', hệ thống tự động loại trừ vùng túi đồ / tooltip (x > 0.55 * w)."""
        img = Image.new("RGB", (2560, 1440), color=(15, 15, 15))
        # find_button_by_text với token "ENTER"
        pos = find_button_by_text(img, "ENTER")
        if pos is not None:
            self.assertLessEqual(pos[0], int(2560 * 0.55), "Đã match chữ ENTER trong vùng túi đồ x > 0.55*w!")

    def test_find_player_avatar_on_real_clicked_pin_capture(self) -> None:
        """Kiểm chứng nhận diện Player Avatar trên capture thật: 20260914_003608_364_CLICKED_PIN_1280_560.png."""
        capture_path = os.path.join(self.captures_dir, "20260914_003608_364_CLICKED_PIN_1280_560.png")
        if not os.path.exists(capture_path):
            self.skipTest(f"Không tìm thấy {capture_path}")

        avatar_pos = find_player_avatar_on_atlas(capture_path)
        self.assertIsNotNone(avatar_pos, "Không tìm thấy Player Avatar trên capture 20260914_003608_364_CLICKED_PIN_1280_560.png")
        
        # Tọa độ thực tế của pin là (1280, 560)
        ax, ay = avatar_pos
        self.assertAlmostEqual(ax, 1280, delta=30, msg=f"Lệch tọa độ X: {ax} != 1280")
        self.assertAlmostEqual(ay, 560, delta=30, msg=f"Lệch tọa độ Y: {ay} != 560")

    def test_find_player_avatar_on_test_player_node_capture(self) -> None:
        """Kiểm chứng nhận diện Player Avatar trên capture thật: test_player_node.png."""
        capture_path = os.path.join(self.captures_dir, "test_player_node.png")
        if not os.path.exists(capture_path):
            self.skipTest(f"Không tìm thấy {capture_path}")

        avatar_pos = find_player_avatar_on_atlas(capture_path)
        self.assertIsNotNone(avatar_pos, "Không tìm thấy Player Avatar trên test_player_node.png")
        ax, ay = avatar_pos
        # Nằm trong vùng đỉnh Great Wall trung tâm Atlas
        self.assertTrue(1150 <= ax <= 1350, f"Tọa độ X avatar {ax} nằm ngoài dải dự kiến 1150..1350")
        self.assertTrue(450 <= ay <= 650, f"Tọa độ Y avatar {ay} nằm ngoài dải dự kiến 450..650")

    def test_find_player_avatar_pin_crop_direct(self) -> None:
        """Kiểm chứng nhận diện Player Avatar trực tiếp trên ảnh crop pin_1280_560.png."""
        pin_path = os.path.join(self.captures_dir, "pin_1280_560.png")
        if not os.path.exists(pin_path):
            self.skipTest(f"Không tìm thấy {pin_path}")

        # pin_1280_560.png kích thước 200x200
        avatar_pos = find_player_avatar_on_atlas(pin_path, return_none_if_missing=False)
        self.assertIsNotNone(avatar_pos)

    def test_player_avatar_fallback_when_missing(self) -> None:
        """Kiểm chứng fallback về vị trí đỉnh Great Wall chuẩn hóa khi return_none_if_missing=False."""
        blank_img = Image.new("RGB", (1920, 1080), color=(0, 0, 0))
        
        # 1. return_none_if_missing=True -> Trả về None
        none_res = find_player_avatar_on_atlas(blank_img, return_none_if_missing=True)
        self.assertIsNone(none_res)

        # 2. return_none_if_missing=False -> Trả về tọa độ chuẩn hóa 1080p: (1280 * 1920/2560 = 960, 560 * 1080/1440 = 420)
        fallback_res = find_player_avatar_on_atlas(blank_img, return_none_if_missing=False)
        self.assertIsNotNone(fallback_res)
        self.assertEqual(fallback_res, (960, 420))


if __name__ == "__main__":
    unittest.main()
