from coopstructs.vectors import Vector2
from coopstructs.toggles import BooleanToggleable, EnumToggleable
from coopgame.gameTemplate import GameTemplate
from coopgraph.gridSelectPolicies import TogglePolicy
from coopgraph.toggles import BooleanToggleable
from cooptools.colors import Color
from coopgame.linedrawing.unitpathhandler import UnitPathHandler
import numpy as np
import coopgame.renderedObjectHandling.MatrixManipulation as mm
from coopgame.grids_graphs.pygridgraphHandler import PyGridGraphHandler
import coopgame.pygamehelpers as help
import pygame
from coopgame.spriteHandling.spritesheet import SpriteSheet
from coopgame.spriteHandling.sprites import AnimatedSprite, SpriteOriginPosition
from enum import Enum
import random as rnd

class Seasons(Enum):
    WINTER = 1
    SPRING = 2
    SUMMER = 3
    FALL = 4

class GridGraphGame(GameTemplate):

    def register_keys(self):
        self.register_action_to_keys((pygame.K_t,),
                                     lambda: self.gg_handler.show_toggled.visibility_toggle())
        self.register_action_to_keys((pygame.K_d,),
                                     lambda: self.gg_handler.allow_diag.visibility_toggle(on_toggle_callbacks=[lambda x: self.redraw_graph()]))
        self.register_action_to_keys((pygame.K_s,),
                                    lambda: self.season_toggle.toggle(on_toggle_callbacks=[lambda x: self.change_season(x)]))
        self.register_action_to_keys((pygame.K_g,),
                                    lambda: self.show_graph_toggle.toggle())

    def __init__(self):
        super().__init__(fullscreen=False)
        self.toggle_key = 'toggle'
        self.unit_path_handler = UnitPathHandler(self.toggle_key)
        self.toggle_bool_policy = TogglePolicy(key=self.toggle_key, toggle=BooleanToggleable(default=True))
        rows = 30
        cols = 20
        self.gg_handler = PyGridGraphHandler(rows, cols)

        self.x_rot = 1.1

        self.grid_surface = None
        self.graph_surface = None
        self.grid_overlay_surface = None

        self.last_hover_grid = None
        self.mouse_down_toggling_on = True

        self.time_since_report_stats = 0

        # Init Game
        self.gg_handler.show_toggled.visibility_toggle()
        self.redraw_graph_grid()


        # Init a tree
        self.season_toggle = EnumToggleable(Seasons)
        for ii in range(0, 5):
            self.init_tree(f"tree_{ii}", Vector2(rnd.randint(0, cols-1), rnd.randint(0, rows-1)))

        # toggles
        self.show_graph_toggle = BooleanToggleable(default=True)
        self.show_grid_toggle = BooleanToggleable(default=True)

    def init_tree(self, name: str, grid_pos: Vector2):
        tree_file = '../coopgame/assets/spriteSheets/489-4891674_tree-sprite-sheet-png.png'
        tree_spritesheet = SpriteSheet(tree_file, n_rows=4, n_columns=15, x_margin_left=17,
                                                 x_padding=34, y_margin_top=15, y_padding=17, y_margin_bottom=1)

        state = self.gg_handler.grid_graph.act_on_grid(grid_pos.y, grid_pos.x, [self.toggle_bool_policy])
        game_pos = self.gg_handler.grid.coord_from_grid_pos(grid_pos, self.game_area_rectangle)
        scaled = help.scaled_points([game_pos], self.get_grid_rotation_matrix())[0]
        tree_sprite = AnimatedSprite(id=name,
                                        init_pos=scaled,
                                        animation_dict={Seasons.WINTER: tuple(tree_spritesheet.load_row_strip(0, colorkey=-1)[:1]),
                                                            Seasons.SPRING: tuple(tree_spritesheet.load_row_strip(0, colorkey=-1)[:15]),
                                                            Seasons.SUMMER: tuple(tree_spritesheet.load_row_strip(1, colorkey=-1)[:15]),
                                                            Seasons.FALL: tuple(tree_spritesheet.load_row_strip(2, colorkey=-1)[:15])},
                                        default_animation_key=Seasons.WINTER,
                                        animation_cycle_ms=500,
                                        sprite_origin_position=SpriteOriginPosition.BOTTOM_MIDDLE,
                                        height=100,
                                        width=100
                                     )
        self.sprites[name] = tree_sprite

    def change_season(self, season):
        for id, sprite in self.sprites.items():
            sprite.set_animation(season)

    def redraw_graph_grid(self):
        self.grid_surface = help.init_surface(self.screen.get_size())
        self.graph_surface = help.init_surface(self.screen.get_size())
        self.grid_overlay_surface = help.init_surface(self.screen.get_size())

        self.gg_handler.redraw_graph_grid_overlay(self.grid_surface,
                                                  self.graph_surface,
                                                  self.grid_overlay_surface,
                                                  self.get_grid_rotation_matrix(),
                                                  predefined_highlights={Vector2(1, 1): Color.PURPLE,
                                                            Vector2(5, 5): Color.YELLOW})


    def redraw_grid_overlay(self):
        self.grid_overlay_surface = help.init_surface(self.screen.get_size())

        self.gg_handler.redraw_grid_overlay(self.grid_overlay_surface,
                                          self.get_grid_rotation_matrix(),
                                          predefined_highlights={Vector2(1, 1): Color.PURPLE,
                                                                 Vector2(5, 5): Color.YELLOW},)

    def redraw_graph(self):
        self.graph_surface = help.init_surface(self.screen.get_size())

        self.gg_handler.redraw_graph(self.graph_surface,
                                          self.get_grid_rotation_matrix(),)

    def draw(self, frames:int, debug_mode: bool = False):
        if self.show_grid_toggle.value:
            self.screen.blit(self.grid_surface, (0, 0))

        if self.show_graph_toggle.value:
            self.screen.blit(self.graph_surface, (0, 0))

        self.redraw_grid_overlay()
        self.screen.blit(self.grid_overlay_surface, (0, 0))

        # draw sprites
        self.sprite_drawer(self.screen)

    def handle_left_mouse_down(self, pressed_keys, mouse_pos_as_vector: Vector2):
        grid_pos = self.gg_handler.mouse_grid_pos(self.game_area_rectangle, help.mouse_pos_as_vector(), self.get_grid_rotation_matrix())

        if grid_pos is not None:
            state = self.gg_handler.grid_graph.act_on_grid(grid_pos.y, grid_pos.x, [self.toggle_bool_policy])
            if state[self.gg_handler.toggle_key] == True:
                self.mouse_down_toggling_on = True
            else:
                self.mouse_down_toggling_on = False

            self.redraw_graph()

    def handle_right_mouse_down(self, pressed_keys, mouse_pos_as_vector: Vector2):
        clicked_pos = self.gg_handler.mouse_grid_pos(self.game_area_rectangle, help.mouse_pos_as_vector(), self.get_grid_rotation_matrix())
        self.gg_handler.pff.set_astar_origin(clicked_pos)

    def need_to_toggle_at_pos(self, mouse_grid_pos):
        toggle_at_pos = self.gg_handler[mouse_grid_pos]
        if toggle_at_pos is None:
            return False

        return self.gg_handler[mouse_grid_pos].value != self.mouse_down_toggling_on

    def handle_hover_over(self, pressed_keys, mouse_pos_as_vector: Vector2):
        mouse_grid_pos = self.gg_handler.mouse_grid_pos(self.game_area_rectangle, help.mouse_pos_as_vector(), draw_scale_matrix=self.get_grid_rotation_matrix())

        if pressed_keys and mouse_grid_pos != self.last_hover_grid and self.need_to_toggle_at_pos(mouse_grid_pos):
            # handle drag across cells
            self.gg_handler.grid.act_on_grid(mouse_grid_pos.y, mouse_grid_pos.x, [self.gg_handler.toggle_bool_policy])

        self.last_hover_grid = mouse_grid_pos

        self.gg_handler.handle_hover_over(window_rect=self.game_area_rectangle,
                                          grid_rotation_matrix=self.get_grid_rotation_matrix())

    def get_grid_rotation_matrix(self):
        orientation = np.array([0, 0, 1])
        rotation_unit_vector = mm.rotation_unit_vector(orientation)
        matrixz = mm.rotateAroundAxis((self.screen_width / 2, self.screen_height / 2, 0), rotation_unit_vector,
                                      np.pi / 4)
        orientation = np.array([1, 0, 0])
        rotation_unit_vector = mm.rotation_unit_vector(orientation)
        matrixx = mm.rotateAroundAxis((self.screen_width / 2, self.screen_height / 2, 0), rotation_unit_vector,
                                      self.x_rot)
        matrix = matrixx.dot(matrixz)
        return matrix

if __name__ == "__main__":
    import logging

    logging.basicConfig(level=logging.INFO)
    logging.getLogger('coopgame').setLevel(logging.INFO)
    g = GridGraphGame()
    g.main()