from coopgame.coordinateConverter import DrawMatrixState, MultiPerspectivePointConverter
from coopgame.renderedObjectHandling.wireframes.WireframeObjects import Cube
import pygame
from coopgame.gameTemplate import GameTemplate
from coopstructs.geometry.vectors.vectorN import Vector3, Vector2
from cooptools.colors import Color
from coopstructs.geometry import Rectangle
from coopgame.renderedObjectHandling.renderedViewArgs import RenderedViewArgs
from coopgame.renderedObjectHandling.wireframes.Wireframe import Wireframe
from coopgame.renderedObjectHandling.renderedObject import RenderedObject
import coopgame.pygamehelpers as help
import coopgame.label_drawing.label_drawing_utils as lab
from coopgame.handleKeyPressedArgs import InputState, InputStateHandler, InputAction, InputEvent, InputEventType, basic_key_actions, CallbackPackage
from coopgame.pygame_k_constant_names import PyKeys, PyMouse

FOCUSED_OBJ = 'cube'
class CoordinateConversionGame(GameTemplate):

    def __init__(self):
        super().__init__(fullscreen=False, input_state_handler=self.define_input_handler())
        pygame.display.set_caption('Wireframe Display')

        self.mppc = MultiPerspectivePointConverter()
        self.matrix_state = DrawMatrixState()

        self.cube = Cube((0, 0, 0), 1)
        self.rendered_objects = {}
        self.focused_object = FOCUSED_OBJ


        self.viewargs = RenderedViewArgs()
        self.radians_per_sec = .1

        self.displayNodes = True
        self.displayEdges = True
        self.displayCenters = True
        self.nodeColour = Color.ORANGE
        self.edgeColour = Color.MAGENTA
        self.centerColour = Color.RED
        self.nodeRadius = 2
        self.centerNodeRadius = 4

    def define_input_handler(self):
        return InputStateHandler(
            quit_callback_package=CallbackPackage(down=lambda x: self.quit()),
            debug_callback_package=CallbackPackage(down=lambda x: self.debug_mode_toggle.toggle()),
            fullscreen_callback_package=CallbackPackage(down=lambda x: self.toggle_fullscreen()),
            key_actions=[
                # OBJ MOVE
                InputAction([InputEvent(PyKeys.K_w, event_type=InputEventType.HELD)], callback=lambda x: self.rendered_objects[self.focused_object].orientation.change_translation(delta_vector=Vector3(0, -1, 0))),
                InputAction([InputEvent(PyKeys.K_a, event_type=InputEventType.HELD)], callback=lambda x: self.rendered_objects[self.focused_object].orientation.change_translation(delta_vector=Vector3(-1, 0, 0))),
                InputAction([InputEvent(PyKeys.K_s, event_type=InputEventType.HELD)], callback=lambda x: self.rendered_objects[self.focused_object].orientation.change_translation(delta_vector=Vector3(0, 1, 0))),
                InputAction([InputEvent(PyKeys.K_d, event_type=InputEventType.HELD)], callback=lambda x: self.rendered_objects[self.focused_object].orientation.change_translation(delta_vector=Vector3(1, 0, 0))),

                #OBJ ROT
                InputAction([InputEvent(PyKeys.K_q, event_type=InputEventType.HELD)], callback=lambda x: self.rendered_objects[self.focused_object].orientation.change_rotation(rads_delta=.1, rotation_axis=Vector3(0, 1, 0))),
                InputAction([InputEvent(PyKeys.K_e, event_type=InputEventType.HELD)], callback=lambda x: self.rendered_objects[self.focused_object].orientation.change_rotation(rads_delta=-.1, rotation_axis=Vector3(0, 1, 0))),

                # CAMERA MOVE
                InputAction([InputEvent(PyKeys.K_LEFT, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_translation(delta_vector=Vector3(-1, 0, 0))),
                InputAction([InputEvent(PyKeys.K_RIGHT, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_translation(delta_vector=Vector3(1, 0, 0))),
                InputAction([InputEvent(PyKeys.K_UP, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_translation(delta_vector=Vector3(0, -1, 0))),
                InputAction([InputEvent(PyKeys.K_DOWN, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_translation(delta_vector=Vector3(0, 1, 0))),

                # CAMERA ROT
                InputAction([InputEvent(PyKeys.K_i, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_rotation(rads_delta=.1, rotation_axis=Vector3(1, 0, 0))),
                InputAction([InputEvent(PyKeys.K_k, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_rotation(rads_delta=-.1, rotation_axis=Vector3(1, 0, 0))),
                InputAction([InputEvent(PyKeys.K_j, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_rotation(rads_delta=.1, rotation_axis=Vector3(0, 1, 0))),
                InputAction([InputEvent(PyKeys.K_l, event_type=InputEventType.HELD)], callback=lambda x: self.viewargs.camera_orientation.change_rotation(rads_delta=-.1, rotation_axis=Vector3(0, 1, 0))),

        ])

    def initialize_game(self):
        pass

    def handle_hover_over(self, mouse_pos_as_vector: Vector2):
        pass

    def handle_left_mouse_down(self, pressed_keys):
        pass

    def handle_right_mouse_down(self, pressed_keys):
        pass

    def handle_mouse_scroll_up(self, pressed_keys):
        self.viewargs.camera_orientation.change_scale(Vector3(1.1, 1.1, 1.1), Vector3(*self.rendered_objects[self.focused_object].camera_center(self.viewargs)[:3]))

    def handle_mouse_scroll_down(self, pressed_keys):
        self.viewargs.camera_orientation.change_scale(Vector3(.9, .9, .9), Vector3(*self.rendered_objects[self.focused_object].camera_center(self.viewargs)[:3]))

    def model_updater(self, delta_time_ms: int):
        pass
        #     self.matrix_state.set_matricies(self.viewargs)
        #     game_area_rect = Rectangle(0, 0, self.screen.get_height(), self.screen.get_width())
        #     self.viewport_points = self.mppc.convert_real_to_viewport([Vector3(point[0], point[1], point[2]) for point in self.cube.nodes],
        #                                                               game_area_rect=game_area_rect,
        #                                                               matrix_state=self.matrix_state)
    def addRenderedObject(self,
                          name: str,
                          wireframe: Wireframe):
        """ Add a named wireframe object. """
        self.rendered_objects[name] = RenderedObject(wireframe)

    def draw(self, frames:int, debug_mode: bool = False):
        self._draw_rendered_objects()
        lab.draw_label(
            hud=self.screen,
            text=f"{self.rendered_objects[self.focused_object].world_center[:3]}",
            args=lab.DrawLabelArgs(),
            pos=(0, self.screen.get_height() - 100)
        )

        lab.draw_label(
            hud=self.screen,
            text=f"{self.rendered_objects[self.focused_object].camera_center(self.viewargs)[:3]}",
            args=lab.DrawLabelArgs(),
            pos=(0, self.screen.get_height() - 50)
        )

        lab.draw_label(
            hud=self.screen,
            text=str(help.mouse_pos()),
            args=lab.DrawLabelArgs(),
            pos=(0, self.screen.get_height())
        )





        # help.draw_text(text=f"{self.rendered_objects[self.focused_object].world_center[:3]}",
        #                hud=self.screen,
        #                offset_rect=Rectangle(0, self.screen.get_height() - 100, 20, self.screen.get_width()))
        # help.draw_text(text=f"{self.rendered_objects[self.focused_object].camera_center(self.viewargs)[:3]}",
        #                hud=self.screen)
        #
        # help.draw_mouse_coord(self.screen,
        #                       offset_rect=Rectangle(0, self.screen.get_height() - 150, 20, self.screen.get_width()))

    def _draw_rendered_objects(self):
        for name, obj in self.rendered_objects.items():
            if self.displayEdges:
                for n1, n2 in obj.camera_edges(self.viewargs):
                    pygame.draw.aaline(self.screen, self.edgeColour.value, n1, n2, 1)

            if self.displayNodes:
                for node in obj.camera_nodes(self.viewargs):
                    pygame.draw.circle(self.screen, self.nodeColour.value, (int(node[0]), int(node[1])), self.nodeRadius, 0)

            if self.displayCenters:
                center = obj.camera_center(self.viewargs)
                pygame.draw.circle(self.screen, self.centerColour.value, (int(center[0]), int(center[1])),
                                   self.centerNodeRadius, 0)


    def sprite_updater(self, delta_time_ms: int):
        pass

    def on_resize(self):
        pass


if __name__ == "__main__":

    cube = Cube((50, 50, 50), 100)


    pv = CoordinateConversionGame()
    pv.addRenderedObject(FOCUSED_OBJ, cube)

    # axis = np.array([1, 0, 0])
    # rotation_vector = axis / (axis ** 2).sum() ** 0.5
    #
    # pv._rotate_all(rotation_vector, np.pi / 3)

    pv.main()