"""
Unit tests for gesture event system.

Tests TouchEvent, GestureType, GestureResponse, and HAL integration.
"""

import unittest
from pyWebLayout.io.gesture import (
    GestureType,
    TouchEvent,
    GestureResponse,
    ActionType
)


class TestGestureType(unittest.TestCase):
    """Test GestureType enum"""

    def test_gesture_types_exist(self):
        """Test all gesture types are defined"""
        self.assertEqual(GestureType.TAP.value, "tap")
        self.assertEqual(GestureType.LONG_PRESS.value, "long_press")
        self.assertEqual(GestureType.SWIPE_LEFT.value, "swipe_left")
        self.assertEqual(GestureType.SWIPE_RIGHT.value, "swipe_right")
        self.assertEqual(GestureType.SWIPE_UP.value, "swipe_up")
        self.assertEqual(GestureType.SWIPE_DOWN.value, "swipe_down")
        self.assertEqual(GestureType.PINCH_IN.value, "pinch_in")
        self.assertEqual(GestureType.PINCH_OUT.value, "pinch_out")
        self.assertEqual(GestureType.DRAG_START.value, "drag_start")
        self.assertEqual(GestureType.DRAG_MOVE.value, "drag_move")
        self.assertEqual(GestureType.DRAG_END.value, "drag_end")


class TestTouchEvent(unittest.TestCase):
    """Test TouchEvent dataclass"""

    def test_init_basic(self):
        """Test basic TouchEvent creation"""
        event = TouchEvent(
            gesture=GestureType.TAP,
            x=450,
            y=320
        )

        self.assertEqual(event.gesture, GestureType.TAP)
        self.assertEqual(event.x, 450)
        self.assertEqual(event.y, 320)
        self.assertIsNone(event.x2)
        self.assertIsNone(event.y2)
        self.assertEqual(event.timestamp_ms, 0)

    def test_init_with_secondary_point(self):
        """Test TouchEvent with secondary point (pinch/drag)"""
        event = TouchEvent(
            gesture=GestureType.PINCH_OUT,
            x=400,
            y=300,
            x2=450,
            y2=350,
            timestamp_ms=12345.678
        )

        self.assertEqual(event.gesture, GestureType.PINCH_OUT)
        self.assertEqual(event.x, 400)
        self.assertEqual(event.y, 300)
        self.assertEqual(event.x2, 450)
        self.assertEqual(event.y2, 350)
        self.assertEqual(event.timestamp_ms, 12345.678)

    def test_from_hal_basic(self):
        """Test parsing TouchEvent from HAL format"""
        hal_data = {
            'gesture': 'tap',
            'x': 450,
            'y': 320
        }

        event = TouchEvent.from_hal(hal_data)

        self.assertEqual(event.gesture, GestureType.TAP)
        self.assertEqual(event.x, 450)
        self.assertEqual(event.y, 320)

    def test_from_hal_complete(self):
        """Test parsing TouchEvent with all fields from HAL"""
        hal_data = {
            'gesture': 'pinch_out',
            'x': 400,
            'y': 300,
            'x2': 450,
            'y2': 350,
            'timestamp': 12345.678
        }

        event = TouchEvent.from_hal(hal_data)

        self.assertEqual(event.gesture, GestureType.PINCH_OUT)
        self.assertEqual(event.x, 400)
        self.assertEqual(event.y, 300)
        self.assertEqual(event.x2, 450)
        self.assertEqual(event.y2, 350)
        self.assertEqual(event.timestamp_ms, 12345.678)

    def test_to_dict(self):
        """Test TouchEvent serialization"""
        event = TouchEvent(
            gesture=GestureType.SWIPE_LEFT,
            x=600,
            y=400,
            timestamp_ms=12345.0
        )

        d = event.to_dict()

        self.assertEqual(d['gesture'], 'swipe_left')
        self.assertEqual(d['x'], 600)
        self.assertEqual(d['y'], 400)
        self.assertIsNone(d['x2'])
        self.assertIsNone(d['y2'])
        self.assertEqual(d['timestamp_ms'], 12345.0)


class TestGestureResponse(unittest.TestCase):
    """Test GestureResponse dataclass"""

    def test_init(self):
        """Test GestureResponse creation"""
        response = GestureResponse(
            action="page_turn",
            data={"direction": "forward", "progress": 0.42}
        )

        self.assertEqual(response.action, "page_turn")
        self.assertEqual(response.data['direction'], "forward")
        self.assertEqual(response.data['progress'], 0.42)

    def test_to_dict(self):
        """Test GestureResponse serialization"""
        response = GestureResponse(
            action="define",
            data={"word": "ephemeral", "bounds": (100, 200, 50, 20)}
        )

        d = response.to_dict()

        self.assertEqual(d['action'], "define")
        self.assertEqual(d['data']['word'], "ephemeral")
        self.assertEqual(d['data']['bounds'], (100, 200, 50, 20))

    def test_to_dict_empty_data(self):
        """Test GestureResponse with empty data"""
        response = GestureResponse(action="none", data={})

        d = response.to_dict()

        self.assertEqual(d['action'], "none")
        self.assertEqual(d['data'], {})


class TestActionType(unittest.TestCase):
    """Test ActionType constants"""

    def test_action_types_defined(self):
        """Test all action type constants are defined"""
        self.assertEqual(ActionType.NONE, "none")
        self.assertEqual(ActionType.PAGE_TURN, "page_turn")
        self.assertEqual(ActionType.NAVIGATE, "navigate")
        self.assertEqual(ActionType.DEFINE, "define")
        self.assertEqual(ActionType.SELECT, "select")
        self.assertEqual(ActionType.ZOOM, "zoom")
        self.assertEqual(ActionType.BOOK_LOADED, "book_loaded")
        self.assertEqual(ActionType.WORD_SELECTED, "word_selected")
        self.assertEqual(ActionType.SHOW_MENU, "show_menu")
        self.assertEqual(ActionType.SELECTION_START, "selection_start")
        self.assertEqual(ActionType.SELECTION_UPDATE, "selection_update")
        self.assertEqual(ActionType.SELECTION_COMPLETE, "selection_complete")
        self.assertEqual(ActionType.AT_START, "at_start")
        self.assertEqual(ActionType.AT_END, "at_end")
        self.assertEqual(ActionType.ERROR, "error")


class TestHALIntegration(unittest.TestCase):
    """Test HAL integration scenarios"""

    def test_hal_tap_flow(self):
        """Test complete HAL tap event flow"""
        # Simulate HAL sending tap event
        hal_data = {
            'gesture': 'tap',
            'x': 450,
            'y': 320,
            'timestamp': 1234567890.123
        }

        # Parse event
        event = TouchEvent.from_hal(hal_data)

        # Verify event
        self.assertEqual(event.gesture, GestureType.TAP)
        self.assertEqual(event.x, 450)
        self.assertEqual(event.y, 320)

        # Simulate business logic response
        response = GestureResponse(
            action=ActionType.WORD_SELECTED,
            data={"word": "hello", "bounds": (440, 310, 50, 20)}
        )

        # Serialize for Flask
        response_dict = response.to_dict()

        self.assertEqual(response_dict['action'], "word_selected")
        self.assertEqual(response_dict['data']['word'], "hello")

    def test_hal_pinch_flow(self):
        """Test complete HAL pinch event flow"""
        # Simulate HAL sending pinch event with two touch points
        hal_data = {
            'gesture': 'pinch_out',
            'x': 400,
            'y': 500,
            'x2': 500,
            'y2': 500,
            'timestamp': 1234567891.456
        }

        event = TouchEvent.from_hal(hal_data)

        self.assertEqual(event.gesture, GestureType.PINCH_OUT)
        self.assertEqual(event.x, 400)
        self.assertEqual(event.x2, 500)

    def test_hal_swipe_flow(self):
        """Test complete HAL swipe event flow"""
        hal_data = {
            'gesture': 'swipe_left',
            'x': 600,
            'y': 400
        }

        event = TouchEvent.from_hal(hal_data)

        self.assertEqual(event.gesture, GestureType.SWIPE_LEFT)

        # Expected response
        response = GestureResponse(
            action=ActionType.PAGE_TURN,
            data={"direction": "forward", "progress": 0.25}
        )

        self.assertEqual(response.action, "page_turn")

    def test_hal_drag_selection_flow(self):
        """Test complete drag selection flow"""
        # Drag start
        start_data = {
            'gesture': 'drag_start',
            'x': 100,
            'y': 200
        }

        start_event = TouchEvent.from_hal(start_data)
        self.assertEqual(start_event.gesture, GestureType.DRAG_START)

        # Drag move
        move_data = {
            'gesture': 'drag_move',
            'x': 300,
            'y': 250
        }

        move_event = TouchEvent.from_hal(move_data)
        self.assertEqual(move_event.gesture, GestureType.DRAG_MOVE)

        # Drag end
        end_data = {
            'gesture': 'drag_end',
            'x': 500,
            'y': 300
        }

        end_event = TouchEvent.from_hal(end_data)
        self.assertEqual(end_event.gesture, GestureType.DRAG_END)


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