from pygame import *
import sys

class pygames:
    def __init__(self, w=800, h=600, title="Pygame-S ", icon_path=None):
        init()
        font.init()
        self.screen_width = w
        self.screen_height = h
        self.screen = display.set_mode((w, h))
        self.set_title(title)
        if icon_path:
            self.set_icon(icon_path)
        self.clock = time.Clock()
        self.running = True
        self.font = font.SysFont("Arial", 30)
        self.sounds = {}
        self.images = {}
        mixer.init()
        self.objects = []
        self.solids = []
        self.score = 0
        self.score_active = False
        self.garbage_collection = False
        self.fps = 60

    def set_title(self, title):
        display.set_caption(str(title))

    def set_icon(self, path):
        icon = image.load(path)
        display.set_icon(icon)
           
    def Error1(self, name):
        raise NameError(f"The file {name} does not exist check the file.")
    
    def load_image(self, name, path):
        try:
            self.images[name] = image.load(path).convert_alpha()
        except:
            self.Error1(name)        

    def image(self, name, x, y, w=None, h=None):
        try:
           img = self.images.get(name)
           if img:              
               if w and h:
                  img = transform.scale(img, (w, h))
               self.screen.blit(img, (x, y))
        except:
            self.Error1(name)        

    def load_sound(self, name, path):
        try:
           self.sounds[name] = mixer.Sound(path)
        except:
              self.Error1(name)

    def play_sound(self, name):
        if name in self.sounds:
            self.sounds[name].play()
        else:
            self.Error1(name)   

    def start_score_counter(self):
        self.score_active = True

    def start_garbage_collecter(self):
        self.garbage_collection = True

    def clean_up(self):
        if self.garbage_collection:
            b = 150 
            self.objects = [
                o for o in self.objects 
                if o.rect.right > -b and o.rect.left < self.screen_width + b and
                   o.rect.bottom > -b and o.rect.top < self.screen_height + b
            ]

    def fill(self, color):
        self.screen.fill(color)

    def background(self, color):
        self.screen.fill(color)
    
    def start_loop(self):
        self.clean_up()
        for item in self.objects:
            if hasattr(item, 'apply_physics'):
                item.apply_physics(self.solids)
            item.draw()
        if self.score_active:
            text_surface = self.font.render(f"Score: {self.score}", True, "white")
            self.screen.blit(text_surface, (10, 10))
    
    def show_score(self, x=10, y=10, color="white"):
      score_surf = self.font.render(f"Score: {self.score}", True, color)
      self.screen.blit(score_surf, (x, y))        
        
    def start(self, *objects): 
        for item in objects:
            if item not in self.objects:
                self.objects.append(item)
    
    def make_solid(self, *objects):
        for item in objects:
            if item not in self.solids:
                self.solids.append(item)
                if item not in self.objects:
                    self.objects.append(item)
                         
    def key(self, name):
        keys = key.get_pressed()
        name = name.lower()
        special_keys = {
            "space": K_SPACE, "esc": K_ESCAPE, "up": K_UP,
            "down": K_DOWN, "left": K_LEFT, "right": K_RIGHT,
            "enter": K_RETURN, "shift": K_LSHIFT, "ctrl": K_LCTRL,
            "tab": K_TAB, "backspace": K_BACKSPACE
        }
        if name in special_keys:
            return keys[special_keys[name]]
        try:
            key_const = globals().get(f"K_{name.upper()}")
            return keys[key_const]
        except AttributeError:
            return False

    def zoom(self, factor):
        self.screen_width = int(self.screen_width * factor)
        self.screen_height = int(self.screen_height * factor)
        self.screen = display.set_mode((self.screen_width, self.screen_height))

    def speed(self, fps):
        self.fps= fps
   
    def update(self):
        display.flip()
        self.clock.tick(self.fps)
  
    def is_running(self):
        for e in event.get():
            if e.type == QUIT:
                self.running = False 
        return self.running         

    def mainloop(self, game_logic):
        while self.running: 
            self.is_running()
            game_logic()
            self.start_loop() 
            self.update()
        quit()
        sys.exit()