import asyncio
import pygame
from maze import maze_gen, get_maze_sz
from coords import Coords
from common import DrawableGameObject, EventHandler, IS_WASM

from game.hero import Hero
from game.wall import Walls
from game.coins import Coins
from game.endlevelmenu import EndLevelMenu
from sound import BackgroundSound


class Scene(DrawableGameObject, EventHandler):
    """основной игровой объект"""

    # кнопки для выхода из игры
    exit_keys = (pygame.K_ESCAPE, pygame.K_q)

    def __init__(
        self,
        assets: dict,
        screen_sz: Coords,
        maze_sz: Coords,
        coins_count: int,
        fps: int,
    ):
        super().__init__(Coords.zero(), None, assets)
        self.maze = maze_gen(*maze_sz)
        maze_sz = get_maze_sz(self.maze)

        box_sz = screen_sz // get_maze_sz(self.maze)
        self.box_sz = box_sz
        self._surface = pygame.display.set_mode(screen_sz)
        self.surface.fill("white")
        self.rect = self.surface.get_rect()
        self.background = pygame.image.load(self.assets["bg1k.png"]).convert_alpha()
        self.background = pygame.transform.scale(self.background, self.rect.size)

        double_bg = pygame.Surface((screen_sz.x * 2, screen_sz.y))
        double_bg.blit(self.background, (0, 0))
        double_bg.blit(self.background, (screen_sz.x, 0))
        self.background = double_bg
        self.bg_shift = 0

        self.total_levels, self.total_coins = 0, 0

        hero_sz = Coords(*map(int, box_sz * 0.8))
        hero_y_offset = (box_sz.y - hero_sz.y) // 2 + box_sz.y
        self.hero = Hero(Coords(0, hero_y_offset), self)
        self.done = False
        self.level_completed = False

        self.maze = maze_gen(6, 6)
        self.walls = Walls(self, self.maze, box_sz)
        self.coins = Coins(self, self.maze, box_sz, coins_count)

        self.end = EndLevelMenu(self)
        self.end.active = False
        self.want_new_level = False
        self.exit_rect = self.get_exit_rect()
        self.fps = fps

        self.sound = BackgroundSound(self.assets["bg.ogg"])

    def get_exit_rect(self) -> pygame.Rect:
        # находим клетку в которой будет выход с карты
        maze_sz = get_maze_sz(self.maze)
        coords = (maze_sz - Coords(1, 2)) * self.box_sz
        rect = pygame.Rect(coords, coords)
        rect.width, rect.height = 1, self.box_sz.y
        return rect.move((self.box_sz.x, 0))

    def check_level_completed(self):
        level_completed = self.exit_rect.colliderect(self.hero.rect)
        if level_completed and not self.level_completed:
            self.total_coins += self.coins.coins_collected
            self.total_levels += 1
            self.end.active = True
            self.hero.active = False
            self.level_completed = True

    def draw(self):
        if self.done:
            return
        self.surface.blit(self.background, (-self.bg_shift, 0))
        if self.level_completed:
            self.end.draw()
        else:
            self.hero.draw()
            self.walls.draw()
            self.coins.draw()

    def scale_box(
        self, surface: pygame.Surface, rect: pygame.Rect, scale_factor: Coords
    ):
        rect.size = self.box_sz
        rect.scale_by_ip(*scale_factor)
        surface = pygame.transform.scale(surface, rect.size)
        return surface, rect

    def handle_keys(self, keys_pressed):
        if self.done:
            return
        if not self.done:
            self.hero.handle_keys(keys_pressed)
            self.check_level_completed()
            self.end.handle_keys(keys_pressed)

    def handle_exit(self, event: pygame.event.Event):
        if IS_WASM:
            return
        if (
            event.type == pygame.QUIT
            or event.type == pygame.KEYDOWN
            and event.key in self.exit_keys
        ):
            self.done = True

    def handle_event(self, event: pygame.event.Event):
        self.handle_exit(event)
        if self.done:
            return
        if event.type == pygame.KEYDOWN and event.key == pygame.K_m:
            self.sound.toggle_mute()
        self.hero.handle_event(event)
        self.check_level_completed()
        self.end.handle_event(event)

    async def event_loop(self):
        self.sound.play()
        clock = pygame.time.Clock()
        while not self.done:
            for event in pygame.event.get():
                self.handle_event(event)
            self.handle_keys(pygame.key.get_pressed())
            self.draw()

            self.bg_shift = (self.bg_shift + 1) % self.rect.width
            pygame.display.flip()
            await asyncio.sleep(0)
            clock.tick(self.fps)