import sys
import pygame
from pygame import mixer
from tetri5.util import ConfigurationManager
from tetri5.util import TextGenerator
from tetri5.entity import PieceGenerator 
from tetri5.entity import Well
from tetri5.entity import Stack
from tetri5.online import MultiplayerService
from tetri5.scene import TitleScene

# TODO improve game assets https://www.spriters-resource.com/nes/tetris/
# TODO should be a singleton and refactor the whole file?
class Game:

    def __init__(self):
        self.fps = -1
        self.tile_size = -1
        self.screen = None
        self.clock = None
        self.current_scene = TitleScene()
        
        # In Game #
        self.current_piece = None
        self.next_piece = None
        self.well = None
        self.stack = None
        self.main_music = None
        self.score = -1

    def init(self) -> None:
        pygame.init()
        TextGenerator.init(ConfigurationManager.get("image", "font"), (20, 20))

        win_width = ConfigurationManager.get("window", "width")
        win_height = ConfigurationManager.get("window", "height")
        win_title = ConfigurationManager.get("window", "title")
        win_icon = ConfigurationManager.get("image", "window-icon")

        self.fps = ConfigurationManager.get("engine", "fps")
        self.tile_size = ConfigurationManager.get("engine", "tile-size")
        self.screen = pygame.display.set_mode((win_width, win_height))
        self.clock = pygame.time.Clock()
        pygame.display.set_caption(win_title)
        pygame.display.set_icon(pygame.image.load(win_icon))  



        self.main_music = mixer.Channel(0)
        self.well = Well((280, 80), ConfigurationManager.get("color", "well-1"), ConfigurationManager.get("color", "well-border-1")) # TODO calculate position later and redo color config for well
        self.stack = Stack(ConfigurationManager.get("color", "stack-1"), ConfigurationManager.get("color", "stack-border-1"))
        self.score = 0
        self.main_music.set_volume(0.7) # TODO add volume to the config
        self.main_music.play(mixer.Sound(ConfigurationManager.get("sound", "main-music")), -1)

    # gets called from the games main loop
    def update(self) -> None:
        # TODO write not initialized exception
        elapsed_time = self.clock.tick(self.fps)

        if self.current_scene:
            self.current_scene.update(elapsed_time)
        else:
            if not self.next_piece:
                self.next_piece = PieceGenerator.get_piece((620, 160))

            if self.current_piece:
                self.current_piece.update(elapsed_time, self)
            else:
                self.current_piece = self.next_piece 
                self.current_piece.move((360 - 620, 100 - 160)) # TODO calculate spawn position correctly
                self.next_piece = PieceGenerator.get_piece((620, 160)) # (360, 100)
                if self.stack and self.current_piece.collide(self.stack): # TODO game over redo
                    pygame.quit()
                    MultiplayerService.quit()
                    sys.exit()

            if self.stack:
                self.stack.update(elapsed_time, self)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                MultiplayerService.quit()
                sys.exit()

    def draw(self) -> None:
        # TODO write not initialized exception

        if self.current_scene:
            self.current_scene.draw(self.screen)
        else:
            # draw window bg
            bg_color = pygame.Color(ConfigurationManager.get("color", "window-bg"))
            self.screen.fill(bg_color)

            # draw all game objects
            if self.next_piece:
                self.next_piece.draw(self.screen)
            if self.well:
                self.well.draw(self.screen)
            if self.stack:
                self.stack.draw(self.screen)
            if self.current_piece:
                self.current_piece.draw(self.screen, self.well, self.stack)
            
            score = str(self.score).zfill(6)
            lines = str(self.stack.lines_completed_count).zfill(4)
            level = str(self.get_level()).zfill(2)

            TextGenerator.draw("Top", (80, 120), self.screen)
            TextGenerator.draw("000000", (80, 140), self.screen)
            TextGenerator.draw("Score", (80, 180), self.screen)
            TextGenerator.draw(score, (80, 200), self.screen)
            TextGenerator.draw("Lines " + lines, (300, 40), self.screen)
            TextGenerator.draw("Next", (600, 120), self.screen)
            TextGenerator.draw("LVL " + level, (600, 220), self.screen)

        # update display
        pygame.display.update()

    def get_level(self) -> int:
        lines_per_level = ConfigurationManager.get("engine", "lines-per-level")
        return 0 if not self.stack else self.stack.lines_completed_count // lines_per_level

    