from coopgame.gameTemplate import GameTemplate, tt
from coopgame.surfaceManager import SurfaceManager, SurfaceRegistryArgs
import coopgame.pygamehelpers as help
import coopgame.handleKeyPressedArgs as hkpa
from voroni import *
from constants import *
from wave_collapse import *
from world import GameModel
from examples.voroni_world.draw_args import *
from cooptools import graphs as grf
from typing import Iterable, Tuple
import pygame_widgets
from coopgame.ui import *
from input_controller import InputController
from behaviorTypes import BehaviorType
import logging
from cooptools import common as cmn

logger = logging.getLogger(__name__)

class SurfaceLayer(CoopEnum):
    REGION_BORDERS = auto()
    REGION_COLORS = auto()
    REGION_LABELS = auto()
    MOUSE_REGION = auto()
    CNXNS = auto()
    POINTS = auto()
    VILLAGE = auto()
    VILLAGERS = auto()
    FOG_OF_WAR = auto()
    DEBUG_REGIONS = auto()
    USER_ROUTE = auto()
    RIVERS = auto()
    # PAUSED = auto()
    SECTOR_TREE = auto()
    INPUT_SURFACE_BACKGROUND = auto()
    INPUT_SURFACE = auto()
    GAME_INFO = auto()

class VoroniGame(GameTemplate):
    def __init__(self,
                 n_regions: int,
                 seed: int = None,
                 window_dims: Tuple[int, int] = None):
        super().__init__(input_state_handler=self.define_input_handler(),
                         screen_width=window_dims[0] if window_dims is not None else None,
                         screen_height=window_dims[1] if window_dims is not None else None
                         )
        self._surface_manager = SurfaceManager(time_tracker=tt)
        self.user_route_def = []
        self.user_route = None

        input_x_off = int(self.ui_side_size()[0] * .20)
        input_y_off = 50
        dims = (int(self.ui_side_size()[0] * .8), 10)
        inp_surf = help.init_surface(self.ui_side_size(), color_key=Color.HOT_PINK)
        self._scout_count_slider = TheSlider(
            surf=inp_surf,
            dims=dims,
            pos= (input_x_off, input_y_off),
            label="Scouts"
        )

        self._farmer_count_slider = TheSlider(
            surf=inp_surf,
            pos= (input_x_off, input_y_off + 60),
            label="Farmers",
            dims=dims,
        )
        self._scout_count_slider.surf.set_colorkey(Color.WHITE.value)

        ic = InputController(
            villager_counts={
                BehaviorType.SCOUT: lambda: self._scout_count_slider.Value,
                BehaviorType.FARM: lambda: self._farmer_count_slider.Value
            }
        )

        self._model = GameModel(input_controller=ic,
                                max_villagers=MAX_VILLAGERS,
                                init_villagers=INIT_VILLAGERS,
                                villager_spawn_ms=VILLAGER_SPAWN_MS,
                                sector_tree_depth=SECTOR_TREE_DEPTH,
                                seconds_per_hr=SECONDS_PER_HR)

        self._scout_count_slider.set_bounds(
            bounds=(0, lambda: self._model.NVillagers)
        )
        self._farmer_count_slider.set_bounds(
            bounds=(0, lambda: self._model.NVillagers)
        )

        self._surface_manager.register_surface_ids(
            surface_draw_callbacks=[
                SurfaceRegistryArgs(id=SurfaceLayer.REGION_COLORS.name, callback=self._get_surface_region_colors, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.REGION_BORDERS.name, callback=self._get_surface_region_borders, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.RIVERS.name, callback=self._get_river_surface, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.VILLAGE.name, callback=self._get_village_surface, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.POINTS.name, callback=self._get_surface_region_points, default_visible=False, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.CNXNS.name, callback=self._get_surface_cnxns, default_visible=False, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.MOUSE_REGION.name, callback=self._get_mouse_region_surface, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.FOG_OF_WAR.name, callback=self._get_fow_surface),
                SurfaceRegistryArgs(id=SurfaceLayer.REGION_LABELS.name, callback=self._get_surface_region_names, default_visible=False, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.VILLAGERS.name, callback=self._get_villager_surface, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.DEBUG_REGIONS.name, callback=self._get_debug_surface, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.USER_ROUTE.name, callback=self._get_user_route, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.SECTOR_TREE.name, callback=self._get_sector_graph_surface, default_visible=False, pos=self.world_window_origin()),
                SurfaceRegistryArgs(id=SurfaceLayer.INPUT_SURFACE_BACKGROUND.name, callback=self._get_input_background_surface, default_visible=True),
                SurfaceRegistryArgs(id=SurfaceLayer.INPUT_SURFACE.name, callback=self._get_input_surface, default_visible=True),
                SurfaceRegistryArgs(id=SurfaceLayer.GAME_INFO.name, callback=self._get_game_info_surface, default_visible=True, pos=self.world_window_origin()),
            ]
        )



        self.n_regions = n_regions
        self.redefine(
            n=self.n_regions,
            seed=seed
        )

    def _handle_left_click(self):
        mouse_reg = self.get_mouse_region()

        if len(self.user_route_def) >= 2:
            self.user_route_def = []
        else:
            self.user_route_def.append(mouse_reg)

        logger.info([x.name for x in self.user_route_def])

        if len(self.user_route_def) == 2:
            self.user_route = self._model.route_between_regions(
                start=self.user_route_def[0],
                end=self.user_route_def[1]
            )
        else:
            self.user_route = None

        self._surface_manager.invalidate([SurfaceLayer.USER_ROUTE.name])

    def redefine(self, n: int, seed:int = None):

        self._model.redefine(
            # world_bounds=(self.screen_width, self.screen_height),
            world_bounds=self.world_window_size(),
            n_regions=n,
            seed=seed
        )
        self._surface_manager.invalidate()


    def ui_side_size(self):
        return (min(max(int(UI_SIDE_WIDTH_PERC * self.screen_width), UI_SIDE_WIDTH_MIN), UI_SIDE_WIDTH_MAX), self.screen_height)

    def world_window_size(self):
        return (self.screen_width - self.ui_side_size()[0], self.screen_height)

    def world_window_origin(self):
        return self.ui_side_size()[0], 0

    def define_input_handler(self):
        return (((
            hkpa.InputStateHandler(
                quit_callback_package=hkpa.CallbackPackage(down=lambda x: self.quit()),
                fullscreen_callback_package=hkpa.CallbackPackage(down=lambda x: self.toggle_fullscreen()),
                key_actions=[
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyKeys.K_r, event_type=hkpa.InputEventType.DOWN)],callback=lambda x: self.redefine()),
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyKeys.K_g, event_type=hkpa.InputEventType.DOWN)], callback=lambda x: self._surface_manager.toggle_visible([SurfaceLayer.CNXNS.name])),
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyKeys.K_KP_PLUS, event_type=hkpa.InputEventType.DOWN)], callback=lambda x: self._surface_manager.show_all()),
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyKeys.K_KP_MINUS, event_type=hkpa.InputEventType.DOWN)], callback=lambda x: self._surface_manager.hide_all()),
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyKeys.K_f, event_type=hkpa.InputEventType.DOWN)], callback=lambda x: self._surface_manager.toggle_visible([SurfaceLayer.FOG_OF_WAR.name])),
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyKeys.K_s, event_type=hkpa.InputEventType.DOWN)], callback=lambda x: self._surface_manager.toggle_visible([SurfaceLayer.SECTOR_TREE.name])),
                    hkpa.InputAction([hkpa.InputEvent(hkpa.PyMouse.LEFT, event_type=hkpa.InputEventType.DOWN)], callback=lambda x: self._handle_left_click()),
            ])
            .with_debug(lambda x: self.debug_mode_toggle.toggle()))
            .with_number_mapping(
                {
                    0: lambda x: self._surface_manager.toggle_visible([SurfaceLayer.REGION_BORDERS.name]),
                    1: lambda x: self._surface_manager.toggle_visible([SurfaceLayer.REGION_LABELS.name]),
                    2: lambda x: self._surface_manager.toggle_visible([SurfaceLayer.POINTS.name]),
                    3: lambda x: self._surface_manager.toggle_visible([SurfaceLayer.REGION_COLORS.name])
                }
            ))
            .with_pause(lambda x: self.paused_toggle.toggle()))

    def _draw_region(self,
                    surf,
                    r: Region,
                     border_color: Color = None,
                     background_color: Color = None,
                     pt_color: Color = None,
                     label_color: Color = None,
                     offset: Tuple[int, int] = None):
        if r is None:
            return

        if offset is None:
            offset = (0, 0)

        if background_color:
            # draw highlighted areas
            pygame.draw.polygon(surf,
                                background_color.value,
                                [(x + offset[0], y + offset[1]) for x, y in r.boundary.exterior.coords])

        if border_color is not None:
            ii = 0
            while ii < len(r.boundary.exterior.coords) - 1:
                start_pos = r.boundary.exterior.coords[ii]
                end_pos = r.boundary.exterior.coords[ii + 1]

                pygame.draw.line(surf,
                                 border_color.value,
                                 vec.add_vectors([offset, start_pos]),
                                 vec.add_vectors([offset, end_pos]),
                                 2)
                ii += 1

        if pt_color is not None:
            # draw points
            pnt.draw_points(
                {
                    (float(x.pt[0] + offset[0]), float(x.pt[1] + offset[1])): pnt.DrawPointArgs(
                        color=pt_color
                    ) for x in self._model.regions.values()
                },
                surface=surf
            )

        if label_color is not None:
            lbl.draw_label(hud=surf,
                           args=lbl.LabelArgs(
                               text=str(r.name),
                               draw_args=lbl.DrawLabelArgs(
                                   color=label_color,
                                   alignment=TextAlignmentType.CENTER
                               ),
                               pos=vec.add_vectors([r.pt, offset]),
                           ))

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def get_mouse_region(self):
        mouse_pos = help.mouse_pos()
        mouse_reg = self._model.closest_region(vec.vector_between(self.world_window_origin(), mouse_pos))

        return mouse_reg

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_surface_region_borders(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.screen.get_size())
        surf.fill(color=Color.BLACK.value)

        # draw all the edges
        for p in self._model.regions.values():
            self._draw_region(surf, p, border_color=VERONI_EDGECOLOR)

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_surface_region_points(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        for p in self._model.regions.values():
            self._draw_region(
                surf=surf,
                pt_color=Color.RED,
                r=p
            )

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_surface_region_colors(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        # draw all the edges
        for p in self._model.regions.values():
            self._draw_region(surf,
                              r=p,
                              background_color=TERRAIN_COLOR_MAP[p.terrain])
        return surf


    def _define_graph_drawer(self,
                             show_graph: bool = False,
                             routes: Iterable[grf.AStarResults] = None):
        return pgh.PyGraphHandler(
            screen=self.screen,
            draw_config=GRAPH_DRAW_CONFIG if show_graph else None,
            graph_getter=lambda: self._model.world_graph,
            route_draw_args_getter=lambda: [(r, ROUTE_DRAW_ARGS) for r in routes] if routes else None,
        )

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_surface_cnxns(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        self._define_graph_drawer(show_graph=True).render(surface=surf)
        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_surface_region_names(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        # draw labels
        for p in self._model.regions.values():
            self._draw_region(surf,
                              r=p,
                              label_color=Color.MAGENTA)

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_village_surface(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        surf.set_alpha(120)

        vill = self._model.regions[self._model.village_id]

        # draw highlighted areas
        self._draw_region(
            surf=surf,
            r=vill,
            background_color=VILLAGE_COLOR
        )

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_fow_surface(self):
        if self._model.regions is None:
            return None

        surf = pygame.image.load(r'C:\Users\Tj Burns\PycharmProjects\coopgame\examples\voroni_world\assets\imgs\fog_of_war.png')
        surf.set_colorkey(Color.BLACK.value)
        surf = pygame.transform.scale(surface=surf, size=self.screen.get_size())

        # draw a black (see through) area for the revealed region
        for p in self._model.regions.values():
            if p.visibility_level == VisibilityLevel.REVEALED:
                self._draw_region(
                    surf=surf,
                    r=p,
                    background_color=Color.BLACK,
                    offset=self.world_window_origin()
                )

            if p.visibility_level == VisibilityLevel.REVEALABLE:
                self._draw_region(
                    surf=surf,
                    r=p,
                    background_color=Color.PINK_ORCHID,
                    border_color=VERONI_EDGECOLOR,
                    offset=self.world_window_origin()
                    # label_color=Color.MAGENTA
                )
            if p.visibility_level == VisibilityLevel.REVEALING:
                self._draw_region(
                    surf=surf,
                    r=p,
                    background_color=Color.LIGHT_BLUE,
                    border_color=VERONI_EDGECOLOR,
                    offset=self.world_window_origin()
                    # label_color=Color.MAGENTA
                )
        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_game_info_surface(self):
        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        left_align = self.world_window_size()[0] - 200

        # Draw world clock
        days, hrs = self._model.world_time()
        lbl.draw_label(hud=surf,
                       args=lbl.LabelArgs(
                           text=f"Day {days}, {hrs}:00",
                           draw_args=lbl.DrawLabelArgs(
                               color=VILLAGER_COLOR,
                               alignment=TextAlignmentType.CENTER
                           ),
                           pos=(left_align, 0),
                       ))

        # Draw villager spawn clock
        lbl.draw_label(hud=surf,
                       args=lbl.LabelArgs(
                           text=f"Next Villager Spawn: {round(self._model.villager_spawn_timer.MsRemaining / 1000.0, 1)}s",
                           draw_args=lbl.DrawLabelArgs(
                               color=VILLAGER_COLOR,
                               alignment=TextAlignmentType.CENTER
                           ),
                           pos=(left_align, 40),
                       ))

        offset = 40
        delta = 25
        for name, villager in self._model.Villagers.items():
            offset += delta
            lbl.draw_label(hud=surf,
                           args=lbl.LabelArgs(
                               text=f"{villager.name} --> {tuple(f'{round(x, 1)}...' for x in villager.Position)}",
                               draw_args=lbl.DrawLabelArgs(
                                   color=VILLAGER_COLOR,
                                   alignment=TextAlignmentType.CENTER
                               ),
                               # pos=(self.screen_width * left_align_perc, self.screen_height * offset),
                               pos=(left_align,  offset)
                           ))

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_villager_surface(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        # draw villager label and point
        for v in self._model.Villagers.values():
            lbl.draw_label(
                hud=surf,
                args=lbl.LabelArgs(
                    text=str(v.name),
                    draw_args=lbl.DrawLabelArgs(
                        color=VILLAGER_COLOR,
                    ),
                    pos=v.waypoint_follower.Transform.Translation.Vector,
                    anchor_point_draw_args=pnt.DrawPointArgs(
                        color=VILLAGER_COLOR,
                        radius=3
                    )
                )
            )

            # Draw arrow to villager final dest
            if ((v.waypoint_follower.NextDestination is not None)
                    and (v.waypoint_follower.Position != v.waypoint_follower.NextDestination.end_pos)):
                line.draw_lines(
                    {line.Line(
                        origin=v.waypoint_follower.Position,
                        destination=v.waypoint_follower.NextDestination.end_pos,
                    ): line.DrawLineArgs(
                        color=Color.SLATE_GRAY,
                        directionality_draw_args=line.DirectionalityIndicatorDrawArgs(
                            color=Color.SLATE_GRAY,
                            height=5,
                            width=5
                        ),

                    )},
                    surface=surf

                )

            # Draw arrow to villager next waypoint
            if ((v.waypoint_follower.CurrentTarget is not None)
                    and (v.waypoint_follower.Position != v.waypoint_follower.CurrentTarget.end_pos)):
                line.draw_lines(
                    {line.Line(
                        origin=v.waypoint_follower.Position,
                        destination=v.waypoint_follower.CurrentTarget.end_pos,
                    ): line.DrawLineArgs(
                        color=VILLAGER_COLOR,
                        directionality_draw_args=line.DirectionalityIndicatorDrawArgs(
                            color=VILLAGER_COLOR,
                            height=5,
                            width=5
                        ),

                    )},
                    surface=surf

                )

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_mouse_region_surface(self):
        if self._model.regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        # draw labels
        region = self.get_mouse_region()

        self._draw_region(surf,
                          r=region,
                          label_color=Color.MAGENTA,
                          border_color=Color.YELLOW)

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_user_route(self):
        if self.user_route is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        self._define_graph_drawer(routes=[self.user_route]).render(surface=surf)
        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_river_surface(self):
        if self._model.rivers is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        gh = pgh.PyGraphHandler(
            screen=self.screen,
            draw_config=RIVER_GRAPH_DRAW_CONFIG,
            graph_getter=lambda: self._model.rivers,
        )

        gh.render(surface=surf)

        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_debug_surface(self):
        if self._model.crash_regions is None:
            return None

        surf = help.init_surface(self.world_window_size())
        surf.fill(color=Color.BLACK.value)

        regions = self._model.crash_regions

        for region in regions:
            self._draw_region(surf,
                              r=region,
                              label_color=Color.MAGENTA,
                              border_color=Color.RED)
        help.draw_arrow(
            surf,
            start=regions[0].pt,
            end=regions[1].pt,
            color=Color.RED,
            leader_line=True
        )
        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_input_background_surface(self):
        surf = pygame.image.load(
            r'C:\Users\Tj Burns\PycharmProjects\coopgame\examples\voroni_world\assets\imgs\side_menu_background.png',
        ).convert_alpha()
        surf = pygame.transform.scale(surface=surf, size=self.ui_side_size())
        return surf

    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_input_surface(self):
        self._scout_count_slider.update()
        self._farmer_count_slider.update()

        '''Update pygame widgets'''
        pygame_widgets.update(self._events)

        return self._scout_count_slider.surf


    @timer(logger=logger, log_level=0, time_tracking_class=tt)
    def _get_sector_graph_surface(self):
        surf = help.init_surface(self.world_window_size())
        # surf.fill(color=Color.BLACK.value)

        sg = self._model.world_sector_map

        sectors_to_draw = [(pos, sector[0], sector[1]) for pos, sector in sg.Sectors.items()]
        sectors_to_draw.sort(key=lambda x: x[2], reverse=True)
        for pos, sect_rect, layer in sectors_to_draw:
            color_map = {
                0: (Color.DARK_BLUE, 3),
                1: (Color.DODGER_BLUE, 2),
                2: (Color.LIGHT_BLUE, 1)
            }

            help.draw_box(
                surface=surf,
                rect=help.Rectangle(pt=(sect_rect[0], sect_rect[1]),
                                    dims=(sect_rect[2], sect_rect[3]),
                                    ),
                width=color_map.get(layer, (0, 1))[1],
                color=color_map.get(layer, (Color.LIGHT_GRAY, ))[0]
            )

            if layer < 2:
                labutils.draw_label(
                    hud=surf,
                    args=labutils.LabelArgs(
                        text=str(pos),
                        pos=(sect_rect[0], sect_rect[1]),
                        draw_args=labutils.DrawLabelArgs(
                            color=color_map.get(layer, (Color.LIGHT_GRAY, ))[0]
                        )
                    ),
                )
        return surf



    def draw(self, frames: int, debug_mode: bool = False):
        self._surface_manager.invalidate([SurfaceLayer.VILLAGERS.name,
                                          SurfaceLayer.MOUSE_REGION.name,
                                          SurfaceLayer.DEBUG_REGIONS.name,
                                          SurfaceLayer.INPUT_SURFACE.name,
                                          SurfaceLayer.GAME_INFO.name])
        self._surface_manager.render(self.screen)
        pygame.display.set_caption(f'Voroni Game: seed {self._model._seed}')



    def on_resize(self):
        self.redefine(seed=self._model._seed)
        self._surface_manager.invalidate()


    def model_updater(self, delta_time_ms: int):
        results = self._model.update(delta_time_ms)

        revealed_regions = []
        if results is not None:
            revealed_regions = cmn.flattened_list_of_lists(x.revealed_regions for x in results)

        if revealed_regions is not None and len(revealed_regions) > 0:
            self._surface_manager.invalidate([SurfaceLayer.FOG_OF_WAR.name])

if __name__ == '__main__':
    import os
    from cooptools.loggingHelpers import BASE_LOG_FORMAT
    logging.basicConfig(format=BASE_LOG_FORMAT, level=logging.DEBUG)
    for log_provider in [
        'cooptools.sectors.sectorTree.sectorTree_SectorComparer',
        'cooptools.physics.kinematic',
        'coopgame.surfaceManager',
        'cooptools.timers',
        'cooptools.graphs.graph',
        'cooptools.graphs.graph_dcs',
        'cooptools.timeTracker.timeTracker',
        'cooptools.sectors.sectorTree.sectorTree'
    ]:
        logging.getLogger(log_provider).setLevel(logging.WARNING)

    for log_provider in [
        'cooptools.graphs.graph_dcs'
    ]:
        logging.getLogger(log_provider).setLevel(logging.INFO)

    def define_file_logger():
        # Ensure the logs directory exists
        if not os.path.exists('logs'):
            os.makedirs('logs')

        # 1. Get the specific logger instance
        logger = logging.getLogger('cooptools.sectors.sectorTree.sectorTree')

        # Set the logger's overall minimum level (handlers can filter further)
        logger.setLevel(logging.DEBUG)

        # 2. Create a FileHandler
        log_file_path = os.path.join('logs', 'app_events.log')
        if os.path.exists(log_file_path):
            os.remove(log_file_path)

        file_handler = logging.FileHandler(log_file_path, mode='a')  # 'a' for append, 'w' for write/overwrite

        # 3. Set the FileHandler's logging level
        # file_handler.setLevel(logging.INFO)  # This handler will only process INFO messages and above

        # 4. Create a Formatter
        formatter = logging.Formatter(
            BASE_LOG_FORMAT,
            datefmt='%Y-%m-%d %H:%M:%S'
        )

        # 5. Add Formatter to the Handler
        file_handler.setFormatter(formatter)

        # 6. Add the Handler to the Logger
        logger.addHandler(file_handler)

    # define_file_logger()
    logging.getLogger('__main__').setLevel(logging.NOTSET)
    g = VoroniGame(
        N_REGIONS,
        # seed=1694791782243067367
        # window_dims=(1500, 750),
    )
    g.run(debug=False)
