from common import pygame, os, json, uuid, deepcopy, dataclass, field
import eb_objects
import eb_terrain_objects
import eb_creature_objects

cell_classes = {"grass_small": eb_terrain_objects.Ground, 
                "sword_default": eb_objects.Item}

main_dir = os.path.dirname(os.path.abspath(__file__))
sprites_dir = os.path.join(main_dir, "res", "sprites") 

@dataclass
class Cell:
    terrain_obj:  any
    item_obj:     None = None
    creature_obj: None = None
    is_target: bool = False

@dataclass
class Map:
    name:             str
    sprites:          dict
    sprites_refresh:  int    = 60
    cells:            dict   = field(default_factory = dict)
    color:            str    = "gray57"
    target_color:     str    = "gold"
    size:             int    = 150
    bord:             int    = 3
    scale:            float  = 1
    cam_x:            int    = 0
    cam_y:            int    = 0
    cell_dist:        int    = 1

    def __post_init__(self):
        self.cells = {}
        with open(self.name, 'r') as file:
            buff = json.load(file)
        for line in range(len(buff)):
            self.cells[line] = []
            for cell in buff[str(line)]:
                final_cell = deepcopy(Cell(cell_classes[cell["terrain_obj"]["sprite_name"]](**cell["terrain_obj"])))
                
                if cell["item_obj"]:
                    final_cell.item_obj = deepcopy(cell_classes[cell["item_obj"]["sprite_name"]](**cell["item_obj"]))
                
                self.cells[line].append(deepcopy(final_cell))   



    def draw_map(self, screen, current_frame, grid = True):
        for j in range(len(self.cells)):
            for i, cell in enumerate(self.cells[j]):
                dd = {"x": int((i * self.size + self.cam_x) * self.scale),
                             "y": int((j * self.size + self.cam_y) * self.scale),
                             "w": int(self.size * self.scale - self.cell_dist),
                             "h": int(self.size * self.scale - self.cell_dist),
                             "spr_up": current_frame % self.sprites_refresh,
                             "sprites": self.sprites, "scale": self.scale,
                             "screen": screen}

                cell.terrain_obj.draw(dd)
                if cell.item_obj:
                    cell.item_obj.draw(dd)
                if cell.creature_obj:
                    cell.creature_obj.draw(dd)

                #if grid:
                #    pygame.draw.rect(screen, self.color, pygame.Rect(dd["x"], dd["y"], dd["w"], dd["h"]), self.bord)
                
@dataclass
class Engine:
    sprites:      dict            = field(default_factory = dict)
    screen:       pygame.Surface  = ((1, 1))
    width:        int             = 1600
    height:       int             = 800
    camera_step:  int             = 10
    scale_step:   float           = 0.01
    
    def __post_init__(self):
        self.sprites = {}
        pygame.init()
        pygame.display.set_caption('Elvenbane')
        self.screen = pygame.display.set_mode((self.width, self.height))
        self.load_sprites()
        print("The engine has started. Sprites were successfully loaded.\n")

    def load_sprites(self, folder_path = sprites_dir):
        self.sprites = {}
        files = [f for f in os.listdir(folder_path) if f.lower().endswith('.png')]
        #TOTAL SLOR - REWRITE THIS FUNC PLS
        groups = {}
        for f in files:
            name = os.path.splitext(f)[0]
            if '_' in name and name.rsplit('_', 1)[0].count('_') >= 1:
                prefix = name.rsplit('_', 1)[0]
                num = int(name.rsplit('_', 1)[1])
                groups.setdefault(prefix, []).append((num, f))

        for prefix, items in groups.items():
            items.sort()
            self.sprites[prefix] = [
                pygame.image.load(os.path.join(folder_path, f)).convert_alpha()
                for num, f in items
            ]

    def main_loop(self):                
        easy_map = Map("def_map.json", self.sprites)
        #sp = eb_objects.Sprite(self.sprites, "elf_watching")
        #gr = pygame.image.load(file_path).convert_alpha()

        clock = pygame.time.Clock()        
        running = True
        unlock = True
        current_frame = 0
        max_fps = 60

        while running:
            # poll for events
            # pygame.QUIT event means the user clicked X to close your window
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False

            # fill the screen with a color to wipe away anything from last frame
            self.screen.fill("chartreuse4")

            easy_map.draw_map(self.screen, current_frame + 1)

            if unlock:
                keys = pygame.key.get_pressed()   
                if keys[pygame.K_w]:
                    easy_map.cam_y += self.camera_step
                if keys[pygame.K_s]:
                    easy_map.cam_y -= self.camera_step
                if keys[pygame.K_a]:
                    easy_map.cam_x += self.camera_step
                if keys[pygame.K_d]:
                    easy_map.cam_x -= self.camera_step
                if keys[pygame.K_q]:
                    easy_map.scale += self.scale_step
                if keys[pygame.K_e] and easy_map.scale >= self.scale_step:
                    easy_map.scale -= self.scale_step
                if keys[pygame.K_ESCAPE]:
                    running = False

            #print(current_frame + 1)
            current_frame = (current_frame + 1) % max_fps

            # flip() the display to put your work on screen
            pygame.display.flip()
            # limits FPS to 60
            clock.tick(max_fps)

        pygame.quit()