import random
import math
from math import sqrt
import ctypes
import sdl2
import sdl2.ext
from .tilemanager import TileManager
from .spritemanager import SpriteManager
from .isogeometry import IsometricGeometry
from .sdl2_utils.gui import SDL2Gui

class SDL2Wrapper(IsometricGeometry, SDL2Gui):
    def __init__(self):
        sdl2.ext.init()
        self.view_size = (800, 600)
        self.target_size = (800, 600)
        self.cell_size = 132
        self.view_offset_x = 400
        self.view_offset_y = 200
        self.surface_width = 0
        self.surface_height = 0
        self.window = sdl2.ext.Window("My Game", size=self.view_size)
        self.window.show()  # Mostra la finestra
        self.renderer = sdl2.ext.Renderer(self.window, flags=sdl2.SDL_RENDERER_ACCELERATED)
        self.tile_managers = {}
        self.sprite_managers = {}
        self.factory = sdl2.ext.SpriteFactory(renderer=self.renderer)
        self.fonts = self.generate_fonts("assets/decterm.ttf")
        self.cursor = (0, 0)
    
    def get_perf_counter(self):
        return int(sdl2.SDL_GetPerformanceCounter())
    
    def handle_events(self):
        for event in sdl2.ext.get_events():
            if event.type == sdl2.SDL_QUIT:
                return "QUIT"
            elif event.type == sdl2.SDL_KEYUP:
                key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
                return f"KEYUP:{key}".lower()
            elif event.type == sdl2.SDL_KEYDOWN:
                key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
                return f"KEYDOWN:{key}".lower()
            elif event.type == sdl2.SDL_MOUSEMOTION:
                x, y = event.motion.x, event.motion.y
                return f"MOUSEMOTION:{x}:{y}"
        return False

    def clear_screen(self, color=(0, 0, 0, 255)):  # Aggiunto valore alfa di default
        sdl2.SDL_SetRenderDrawColor(self.renderer.sdlrenderer, *color)
        sdl2.SDL_RenderClear(self.renderer.sdlrenderer)

    def present_renderer(self):
        sdl2.SDL_RenderPresent(self.renderer.sdlrenderer)

    def quit(self):
        sdl2.SDL_Quit()
        
    def load_spritesheet(self, name, path):
        surface = sdl2.ext.load_image(path.replace('.json', '.png'))
        texture = sdl2.ext.Texture(self.renderer, surface)
        self.sprite_managers[name] = SpriteManager(path, surface, texture, self.cell_size)
        
    def load_tilesheet(self, name, path):
        surface = sdl2.ext.load_image(path)
        texture = sdl2.ext.Texture(self.renderer, surface)
        
        self.tile_managers[name] = TileManager(path.replace('.png', '.xml'), surface, texture, self.cell_size)
        
    def load_sprite(self, spritesheet, name):
        return self.tile_managers[spritesheet].get_tile_rect(name)
            
    def render_sprite(self, name, x, y, frame, occlusion=0):
        srcrect, total_frames = self.sprite_managers[name].get_frame_rect(frame)
        if occlusion:
            original_color_mods_r_g_b_a = self.apply_texture_color_mdod(self.sprite_managers[name].spritesheet_texture, occlusion)
        self.renderer.copy(self.sprite_managers[name].spritesheet_texture, 
                           dstrect=(x, y, self.cell_size, self.cell_size),
                            srcrect=srcrect)
        if occlusion:
            sdl2.SDL_SetTextureColorMod(self.sprite_managers[name].spritesheet_texture.tx,
                                *original_color_mods_r_g_b_a)
        return (frame + 1) % total_frames
    
    def render_tile(self, spritesheet_name, cell, x, y):
        tile_name = cell.get('tile')
        occlusion = cell.get('occlusion', 0)
        texture = self.tile_managers[spritesheet_name].get_tilesheet_texture()
        tile_rect = self.tile_managers[spritesheet_name].get_tile_rect(tile_name)
        
        if tile_rect is not None:
            iso_x, iso_y = self.iso_transform(x, y)
            y_offset = self.cell_size - tile_rect[3]
            dst_rect = (iso_x, iso_y + y_offset,
                        tile_rect[2], tile_rect[3])
            
            # Salva i valori originali dei moduli di colore
            original_color_mods_r_g_b_a = self.apply_texture_color_mdod(texture, occlusion)
            
            # Copia la texture con il nuovo modulo di colore
            self.renderer.copy(self.tile_managers[spritesheet_name].get_tilesheet_texture(),
                            sdl2.SDL_Rect(*tile_rect), 
                            sdl2.SDL_Rect(*dst_rect))
            
            sdl2.SDL_SetTextureColorMod(texture.tx, *original_color_mods_r_g_b_a)
            
    def render_tile_shadow(self, spritesheet_name, cell, x, y):
        tile_name = cell.get('tile')
        occlusion = cell.get('occlusion', 0)

    def create_background(self, map, spritesheet_name):
        self.surface_width = round(self.cell_size * len(map[0])*sqrt(2))
        self.surface_height = round(self.cell_size//2 * len(map)*sqrt(2))
        tilesheet_surface = self.tile_managers[spritesheet_name].get_tilesheet_surface()
        bg_surface = sdl2.SDL_CreateRGBSurface(0, self.surface_width, self.surface_height, 32, 0, 0, 0, 0)
        
        def blit_tile(tile, x, y):
            tile_rect = self.tile_managers[spritesheet_name].get_tile_rect(tile)
            if tile_rect is not None:
                vertical_offset = self.cell_size - tile_rect[3]
                horizontal_offset = (self.cell_size - tile_rect[2])
                iso_x, iso_y = self.iso_transform(x, y)
                iso_y += vertical_offset
                iso_x += horizontal_offset
                dst_rect = (iso_x, iso_y,
                            tile_rect[2], tile_rect[3])
                sdl2.SDL_BlitSurface(tilesheet_surface,
                                     sdl2.SDL_Rect(*tile_rect), 
                                     bg_surface, 
                                     sdl2.SDL_Rect(*dst_rect))
                #sdl2.SDL_FillRect(bg_surface, sdl2.SDL_Rect(*dst_rect), sdl2.SDL_MapRGB(bg_surface.contents.format, 0, 0, 255))
    
        for y, row in enumerate(map):
            for x, cell in enumerate(row):
                tile_name = cell.get('tile')
                blit_tile(tile_name, x, y)
    
        self.background_texture = self.factory.from_surface(bg_surface)
        self.apply_texture_color_mdod(self.background_texture, 0.8)
        
    
    def render_texture_to_texture(self, src_texture, dst_texture, srcrect, dstrect):
        self.renderer.copy(src_texture, srcrect, dstrect)
        
    def render_background(self):
        self.renderer.copy(self.background_texture, 
                           dstrect=(0, 0, self.surface_width, self.surface_height),
                           srcrect=(0,0, self.surface_width, self.surface_height))
            
    def get_frame_time(self, perf_counter):
        return (sdl2.SDL_GetPerformanceCounter() - perf_counter) / sdl2.SDL_GetPerformanceFrequency() *1000       
     
    def delay_frame(self, frame_time, target):
            self.performance = (frame_time) 
            if self.performance < target:
                delay = target - round(self.performance)
            else:
                delay = 0
            sdl2.SDL_Delay(delay)

    def draw_cursor(self):
        x, y = self.cursor
        x += self.view_offset_x 
        y -= self.view_offset_y 
        c_x, c_y = self.inv_iso_transform(x, y)
        iso_x, iso_y = self.iso_transform(c_x, c_y)
        iso_y += self.cell_size // 2
        self.renderer.draw_line(points=[(iso_x, iso_y), (iso_x + self.cell_size//2, iso_y + self.cell_size//4)], color=(255, 0, 0, 255))
        self.renderer.draw_line(points=[(iso_x + self.cell_size//2, iso_y + self.cell_size//4), (iso_x + self.cell_size, iso_y)], color=(255, 0, 0, 255))
        self.renderer.draw_line(points=[(iso_x + self.cell_size, iso_y), (iso_x + self.cell_size//2, iso_y - self.cell_size//4)], color=(255, 0, 0, 255))
        self.renderer.draw_line(points=[(iso_x + self.cell_size//2, iso_y - self.cell_size//4), (iso_x, iso_y)], color=(255, 0, 0, 255))
        return c_x, c_y
    
    def apply_texture_color_mdod(self, texture, occlusion):
        color_mod_r = int(255 * (1 - occlusion))
        color_mod_g = int(255 * (1 - occlusion))
        color_mod_b = int(255 * (1 - occlusion))
        original_color_mods_r_g_b_a = [0] * 3
        r_ptr = ctypes.pointer(ctypes.c_ubyte())
        g_ptr = ctypes.pointer(ctypes.c_ubyte())
        b_ptr = ctypes.pointer(ctypes.c_ubyte())
        sdl_texture = texture.texture if hasattr(texture, 'texture') else texture.tx
        sdl2.SDL_GetTextureColorMod(sdl_texture,
                        r_ptr,
                        g_ptr,
                        b_ptr)
        original_color_mods_r_g_b_a[0] = r_ptr.contents.value
        original_color_mods_r_g_b_a[1] = g_ptr.contents.value
        original_color_mods_r_g_b_a[2] = b_ptr.contents.value
        sdl2.SDL_SetTextureColorMod(sdl_texture,
                                color_mod_r,
                                color_mod_g,
                                color_mod_b)
        return original_color_mods_r_g_b_a
    
    def render_tile_shadow(self, x, y, darkness=0):
        iso_x, iso_y = self.iso_transform(x, y)
        iso_y += self.cell_size // 2
        self.renderer.copy(self.shadow_texture, 
                           dstrect=(iso_x, iso_y, self.cell_size, self.cell_size),
                           srcrect=(0, 0, self.cell_size, self.cell_size))