from pathlib import Path

import pyray as ray

from libs.animation import Animation
from libs.audio import audio
from libs.utils import (
    OutlinedText,
    draw_scaled_texture,
    get_current_ms,
    is_l_don_pressed,
    is_l_kat_pressed,
    is_r_don_pressed,
    is_r_kat_pressed,
    load_all_textures_from_zip,
    load_texture_from_zip,
)


class State:
    SELECT_SIDE = 0
    SELECT_MODE = 1

class EntryScreen:
    def __init__(self, width: int, height: int):
        self.width = width
        self.height = height
        self.screen_init = False
        self.box_titles: list[tuple[OutlinedText, OutlinedText]] = [(OutlinedText('演奏ゲーム', 50, ray.Color(255, 255, 255, 255), ray.Color(109, 68, 24, 255), outline_thickness=5, vertical=True),
        OutlinedText('演奏ゲーム', 50, ray.Color(255, 255, 255, 255), ray.Color(0, 0, 0, 255), outline_thickness=5, vertical=True)),
        (OutlinedText('ゲーム設定', 50, ray.Color(255, 255, 255, 255), ray.Color(109, 68, 24, 255), outline_thickness=5, vertical=True),
        OutlinedText('ゲーム設定', 50, ray.Color(255, 255, 255, 255), ray.Color(0, 0, 0, 255), outline_thickness=5, vertical=True))]

    def load_textures(self):
        self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/entry.zip'))
        self.texture_black = load_texture_from_zip(Path('Graphics/lumendata/attract/movie.zip'), 'movie_img00000.png')

    def unload_textures(self):
        for group in self.textures:
            for texture in self.textures[group]:
                ray.unload_texture(texture)

    def load_sounds(self):
        sounds_dir = Path("Sounds")
        self.sound_don = audio.load_sound(sounds_dir / "inst_00_don.wav")
        self.sound_kat = audio.load_sound(sounds_dir / "inst_00_katsu.wav")
        self.bgm = audio.load_sound(sounds_dir / "entry" / "JINGLE_ENTRY [1].ogg")

    def on_screen_start(self):
        if not self.screen_init:
            self.load_textures()
            self.load_sounds()
            self.side = 1
            self.selected_box = 0
            self.num_boxes = 2
            self.state = State.SELECT_SIDE
            self.screen_init = True
            self.drum_move_1 = None
            self.drum_move_2 = None
            self.drum_move_3 = None
            self.cloud_resize = None
            self.cloud_texture_change = None
            self.cloud_fade = None
            self.fade_out = None
            self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.1, reverse_delay=200)
            self.side_select_fade = Animation.create_fade(100, initial_opacity=0.0, final_opacity=1.0)
            self.bg_flicker = Animation.create_fade(500, initial_opacity=0.5, final_opacity=0.4, reverse_delay=0)
            audio.play_sound(self.bgm)

    def on_screen_end(self, next_screen: str):
        self.screen_init = False
        self.unload_textures()
        audio.stop_sound(self.bgm)
        return next_screen

    def handle_input(self):
        if self.fade_out is not None:
            return
        if self.state == State.SELECT_SIDE:
            if is_l_don_pressed() or is_r_don_pressed():
                if self.side == 1:
                    return self.on_screen_end("TITLE")
                self.drum_move_1 = Animation.create_move(350, total_distance=-295, ease_out='quadratic')
                self.drum_move_2 = Animation.create_move(200, total_distance=50, delay=self.drum_move_1.duration, ease_in='quadratic')
                self.drum_move_3 = Animation.create_move(350, total_distance=-170, delay=self.drum_move_1.duration+self.drum_move_2.duration, ease_out='quadratic')
                self.cloud_resize = Animation.create_texture_resize(350, initial_size=0.75, final_size=1.0)
                self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.2, reverse_delay=200, delay=self.cloud_resize.duration)
                textures = ((0, 83.35, 45), (83.35, 166.7, 48), (166.7, 250, 49), (250, 333, 50))
                self.cloud_texture_change = Animation.create_texture_change(333, textures=textures, delay=self.drum_move_1.duration+self.drum_move_2.duration+self.drum_move_3.duration)
                self.cloud_fade = Animation.create_fade(83.35, delay=self.drum_move_1.duration+self.drum_move_2.duration+self.drum_move_3.duration+self.cloud_texture_change.duration)
                self.state = State.SELECT_MODE
                audio.play_sound(self.sound_don)
            if is_l_kat_pressed():
                audio.play_sound(self.sound_kat)
                self.side = max(0, self.side - 1)
            if is_r_kat_pressed():
                audio.play_sound(self.sound_kat)
                self.side = min(2, self.side + 1)
        elif self.state == State.SELECT_MODE:
            if is_l_don_pressed() or is_r_don_pressed():
                audio.play_sound(self.sound_don)
                self.fade_out = Animation.create_fade(160)
            if is_l_kat_pressed():
                audio.play_sound(self.sound_kat)
                self.selected_box = max(0, self.selected_box - 1)
            if is_r_kat_pressed():
                audio.play_sound(self.sound_kat)
                self.selected_box = min(self.num_boxes, self.selected_box + 1)

    def update(self):
        self.on_screen_start()
        self.side_select_fade.update(get_current_ms())
        self.bg_flicker.update(get_current_ms())
        if self.bg_flicker.is_finished:
            self.bg_flicker.restart()
        if self.drum_move_1 is not None:
            self.drum_move_1.update(get_current_ms())
        if self.drum_move_2 is not None:
            self.drum_move_2.update(get_current_ms())
        if self.drum_move_3 is not None:
            self.drum_move_3.update(get_current_ms())
        if self.cloud_resize is not None:
            self.cloud_resize.update(get_current_ms())
        if self.cloud_texture_change is not None:
            self.cloud_texture_change.update(get_current_ms())
        if self.cloud_fade is not None:
            self.cloud_fade.update(get_current_ms())
        self.cloud_resize_loop.update(get_current_ms())
        if self.cloud_resize_loop.is_finished:
            self.cloud_resize_loop = Animation.create_texture_resize(200, initial_size=1.0, final_size=1.1, reverse_delay=200)
        if self.fade_out is not None:
            self.fade_out.update(get_current_ms())
            if self.fade_out.is_finished:
                if self.selected_box == 0:
                    return self.on_screen_end("SONG_SELECT")
                elif self.selected_box == 1:
                    return self.on_screen_end("SETTINGS")
        return self.handle_input()

    def draw_background(self):
        bg_texture = self.textures['entry'][368]
        src = ray.Rectangle(0, 0, bg_texture.width, bg_texture.height)
        dest = ray.Rectangle(0, 0, self.width, bg_texture.height)
        ray.draw_texture_pro(bg_texture, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)

        ray.draw_texture(self.textures['entry'][369], (self.width // 2) - (self.textures['entry'][369].width // 2), (self.height // 2) - self.textures['entry'][369].height, ray.WHITE)
        ray.draw_texture(self.textures['entry'][370], 0, (self.height // 2) - (self.textures['entry'][370].height // 2), ray.WHITE)
        ray.draw_texture(self.textures['entry'][371], (self.width // 2) - (self.textures['entry'][371].width // 2), (self.height // 2) - (self.textures['entry'][371].height // 2) + 10, ray.WHITE)
        ray.draw_texture(self.textures['entry'][372], 0, 0, ray.WHITE)
        ray.draw_texture(self.textures['entry'][373], self.width - self.textures['entry'][373].width, 0, ray.WHITE)
        draw_scaled_texture(self.textures['entry'][374], -7, -15, 2.0, ray.fade(ray.WHITE, self.bg_flicker.attribute))

    def draw_footer(self):
        ray.draw_texture(self.textures['entry'][375], 1, self.height - self.textures['entry'][375].height + 7, ray.WHITE)
        if self.state == State.SELECT_SIDE or self.side != 0:
            ray.draw_texture(self.textures['entry'][376], 1, self.height - self.textures['entry'][376].height + 1, ray.WHITE)
        if self.state == State.SELECT_SIDE or self.side != 2:
            ray.draw_texture(self.textures['entry'][377], 2 + self.textures['entry'][377].width, self.height - self.textures['entry'][376].height + 1, ray.WHITE)

    def draw_side_select(self, fade):
        color = ray.fade(ray.WHITE, fade)
        left_x, top_y, right_x, bottom_y = 238, 108, 979, 520
        ray.draw_texture(self.textures['entry'][205], left_x, top_y, color)
        ray.draw_texture(self.textures['entry'][208], right_x, top_y, color)
        ray.draw_texture(self.textures['entry'][204], left_x, bottom_y, color)
        ray.draw_texture(self.textures['entry'][207], right_x, bottom_y, color)

        texture = self.textures['entry'][209]
        src = ray.Rectangle(0, 0, texture.width, texture.height)
        dest = ray.Rectangle(left_x + self.textures['entry'][205].width, top_y, right_x - left_x - (self.textures['entry'][205].width), texture.height)
        ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
        texture = self.textures['entry'][210]
        src = ray.Rectangle(0, 0, texture.width, texture.height)
        dest = ray.Rectangle(left_x + self.textures['entry'][205].width, bottom_y, right_x - left_x - (self.textures['entry'][205].width), texture.height)
        ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)

        texture = self.textures['entry'][203]
        src = ray.Rectangle(0, 0, texture.width, texture.height)
        dest = ray.Rectangle(left_x, top_y + self.textures['entry'][205].height, texture.width, bottom_y - top_y - (self.textures['entry'][205].height))
        ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
        texture = self.textures['entry'][206]
        src = ray.Rectangle(0, 0, texture.width, texture.height)
        dest = ray.Rectangle(right_x, top_y + self.textures['entry'][205].height, texture.width, bottom_y - top_y - (self.textures['entry'][205].height))
        ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)

        texture = self.textures['entry'][202]
        src = ray.Rectangle(0, 0, texture.width, texture.height)
        dest = ray.Rectangle(left_x + self.textures['entry'][205].width, top_y + self.textures['entry'][205].height, right_x - left_x - (self.textures['entry'][205].width), bottom_y - top_y - (self.textures['entry'][205].height))
        ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)

        ray.draw_texture(self.textures['entry'][226], 384, 144, color)

        cursor_x = 261
        cursor_texture = self.textures['entry'][230]
        flip = 1
        if self.side == 0:
            texture = self.textures['entry'][229]
            flip = -1
        else:
            texture = self.textures['entry'][232]
        ray.draw_texture(texture, 261, 400, color)

        if self.side == 1:
            texture = self.textures['entry'][76]
            cursor_texture = self.textures['entry'][77]
            cursor_x = 512
        else:
            texture = self.textures['entry'][228]
        ray.draw_texture(texture, 512, 400, color)
        ray.draw_texture(self.textures['entry'][201], 512, 408, color)

        if self.side == 2:
            texture = self.textures['entry'][233]
            cursor_x = 762
        else:
            texture = self.textures['entry'][227]
        ray.draw_texture(texture, 762, 400, color)

        src = ray.Rectangle(0, 0, cursor_texture.width * flip, cursor_texture.height)
        dest = ray.Rectangle(cursor_x, 400, cursor_texture.width, cursor_texture.height)
        ray.draw_texture_pro(cursor_texture, src, dest, ray.Vector2(0, 0), 0, color)

    def draw_player_drum(self):
        move_x = 0
        if self.drum_move_3 is not None:
            move_x = int(self.drum_move_3.attribute)
        if self.side == 0:
            drum_texture = self.textures['entry'][366]
            x = 160
        else:
            drum_texture = self.textures['entry'][367]
            x = 780
            move_x = move_x * -1
        move_y = 0
        if self.drum_move_1 is not None:
            move_y = int(self.drum_move_1.attribute)
            if self.drum_move_2 is not None:
                move_y += int(self.drum_move_2.attribute)
        ray.draw_texture(drum_texture, x + move_x, 720 + move_y, ray.WHITE)
        if self.cloud_resize is not None and not self.cloud_resize.is_finished:
            scale = self.cloud_resize.attribute
        else:
            scale = max(1, self.cloud_resize_loop.attribute)
        texture_index = 45
        if self.cloud_texture_change is not None and self.cloud_texture_change.attribute != 0:
            texture_index = self.cloud_texture_change.attribute
        color = ray.fade(ray.WHITE, 1.0)
        if self.cloud_fade is not None:
            color = ray.fade(ray.WHITE, self.cloud_fade.attribute)
        draw_scaled_texture(self.textures['entry'][texture_index], x + move_x - int(160 * (scale-1)), 720 + move_y - 200 - int(160 * (scale-1)), scale, color)

    def draw_mode_select(self, fade):
        self.draw_player_drum()
        color = ray.fade(ray.WHITE, fade)
        if self.cloud_fade is not None and self.cloud_fade.is_finished:
            box_width = self.textures['entry'][262].width
            spacing = 80
            push_distance = 50
            total_width = self.num_boxes * box_width + (self.num_boxes - 1) * spacing
            start_x = self.width//2 - total_width//2
            y = self.height//2 - (self.textures['entry'][262].height//2) - 15
            for i in range(self.num_boxes):
                x_pos = start_x + i * (box_width + spacing)
                push_offset = 0
                if i != self.selected_box:
                    if i < self.selected_box:
                        push_offset = -push_distance
                    else:
                        push_offset = push_distance
                final_x = x_pos + push_offset
                ray.draw_texture(self.textures['entry'][262], final_x, y, color)
                if i == self.selected_box:
                    ray.draw_texture(self.textures['entry'][302], final_x, y, color)
                    texture = self.textures['entry'][304]
                    src = ray.Rectangle(0, 0, texture.width, texture.height)
                    dest = ray.Rectangle(final_x + self.textures['entry'][302].width, y, 100 - self.textures['entry'][302].width, texture.height)
                    ray.draw_texture_pro(texture, src, dest, ray.Vector2(0, 0), 0, color)
                    ray.draw_texture(self.textures['entry'][303], final_x+100, y, color)

                    box_title = self.box_titles[i][1]
                    src = ray.Rectangle(0, 0, box_title.texture.width, box_title.texture.height)
                    dest = ray.Rectangle(final_x + 12, y + 20, box_title.texture.width, box_title.texture.height)
                    box_title.draw(src, dest, ray.Vector2(0, 0), 0, color)
                else:
                    box_title = self.box_titles[i][0]
                    src = ray.Rectangle(0, 0, box_title.texture.width, box_title.texture.height)
                    dest = ray.Rectangle(final_x + 9, y + 20, box_title.texture.width, box_title.texture.height)
                    box_title.draw(src, dest, ray.Vector2(0, 0), 0, color)

    def draw(self):
        self.draw_background()
        if self.state == State.SELECT_SIDE:
            self.draw_side_select(self.side_select_fade.attribute)
        elif self.state == State.SELECT_MODE:
            if self.fade_out is not None:
                self.draw_mode_select(self.fade_out.attribute)
            else:
                self.draw_mode_select(1.0)
        self.draw_footer()

        ray.draw_texture(self.textures['entry'][320], 0, 0, ray.WHITE)

        if self.fade_out is not None and self.fade_out.is_finished:
            src = ray.Rectangle(0, 0, self.texture_black.width, self.texture_black.height)
            dest = ray.Rectangle(0, 0, self.width, self.height)
            ray.draw_texture_pro(self.texture_black, src, dest, ray.Vector2(0, 0), 0, ray.WHITE)
