"""
Unit tests for TASK-IMPL-PYTHON-IPC-GUI
- CoreShmBridge threading lock on SPSC command ring buffer
- Non-blocking sound triggers in GUI
- Max 1,000 lines limit in Control Center log textbox
- attach_to_default_desktop safe handle cleanup
"""

import os
import sys
import threading
import unittest
from unittest.mock import MagicMock, patch

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from src.assistant_tool.core_shm_bridge import CoreShmBridge
from src.assistant_tool.screen_capturer import attach_to_default_desktop


class TestPythonIpcGuiNonblocking(unittest.TestCase):
    def test_core_shm_bridge_cmd_lock(self):
        bridge = CoreShmBridge()
        self.assertTrue(hasattr(bridge, "_cmd_lock"))
        # Verify it is a lock
        self.assertTrue(isinstance(bridge._cmd_lock, type(threading.Lock())))

        # When SHM is None, calls safely return False
        self.assertFalse(bridge.send_panic_stop())
        self.assertFalse(bridge.send_recalibrate_xyz())
        self.assertFalse(bridge.send_trigger_auto_login())
        self.assertFalse(bridge.send_trigger_world_map_travel(1, 0))

    def test_core_shm_bridge_write_under_lock(self):
        bridge = CoreShmBridge()
        # Mock _shm buffer of at least 4MB
        fake_shm = bytearray(4 * 1024 * 1024)
        bridge._shm = fake_shm

        mock_lock = MagicMock()
        bridge._cmd_lock = mock_lock

        res1 = bridge.send_panic_stop()
        self.assertTrue(res1)
        self.assertEqual(mock_lock.__enter__.call_count, 1)

        res2 = bridge.send_recalibrate_xyz()
        self.assertTrue(res2)
        self.assertEqual(mock_lock.__enter__.call_count, 2)

        res3 = bridge.send_trigger_auto_login()
        self.assertTrue(res3)
        self.assertEqual(mock_lock.__enter__.call_count, 3)

        res4 = bridge.send_trigger_world_map_travel(1, 0)
        self.assertTrue(res4)
        self.assertEqual(mock_lock.__enter__.call_count, 4)

    def test_attach_to_default_desktop_safe_cleanup(self):
        # Must execute without exception
        res = attach_to_default_desktop()
        # Handle or None returned, no unhandled exceptions
        self.assertTrue(res is not None or res is None)

    def test_control_center_log_limit(self):
        from src.assistant_tool.control_center import ControlCenterApp
        app = ControlCenterApp()
        try:
            app.update()
            # Clear log first
            app._clear_log()

            # Insert 1050 lines
            for i in range(1050):
                app._append_log(f"Line {i}")

            app.update()
            # Count lines in log_textbox
            num_lines = int(app.log_textbox.index("end-1c").split(".")[0])
            self.assertLessEqual(num_lines, 1001)
        finally:
            app.on_closing()

    def test_gui_nonblocking_beep(self):
        from src.assistant_tool.control_center import ControlCenterApp
        app = ControlCenterApp()
        try:
            with patch("src.assistant_tool.control_center.beep_panic") as mock_beep:
                app._on_panic_stop_hotkey()
                # Audio feedback non-blocking worker was dispatched for panic beep
                self.assertTrue(mock_beep.called)
        finally:
            app.on_closing()

    def test_overlay_gui_nonblocking_beep(self):
        from src.assistant_tool.gold_tracker import GoldTracker
        from src.assistant_tool.log_watcher import LogWatcher
        from src.assistant_tool.market_advisor import MarketAdvisor
        from src.assistant_tool.overlay_gui import OverlayHUD

        gt = GoldTracker(50000)
        lw = LogWatcher("dummy_log.txt")
        ma = MarketAdvisor(gt)

        hud = OverlayHUD(gold_tracker=gt, log_watcher=lw, market_advisor=ma)
        try:
            with patch("src.assistant_tool.overlay_gui.enqueue_beep") as mock_beep:
                hud._on_low_hp_alert(10, 100, 10.0)
                self.assertTrue(mock_beep.called)
        finally:
            hud.destroy()


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