import itertools
import platform
from sys import exit

from file_io import read_json, write_json
from sprites import load_file
from utilities import Board, Button, Smiley, Timer, pg, prompt_file, screen

if platform.system() == "Windows":
    sys_name = "Windows"
    import win32api  # type: ignore
    import win32gui  # type: ignore
    dc = win32gui.GetDC(0)
    white = win32api.RGB(255, 255, 255)
elif platform.system() == "Linux":
    sys_name = "Linux"
elif platform.system() == "Darwin":
    sys_name = "Mac"


class Pysweeper:
    def __init__(self,
                 width: int,
                 height: int,
                 bombs: int,
                 jr_reveal: bool = False) -> None:
        self.width = width
        self.height = height
        self.clicks = 0
        self.flags = 0
        self.question_marks = 0
        self.board = Board(width, height, bombs)
        self.bombs = self.board.bomb_count
        self.smiley = Smiley(x=(self.board.left_offset - 32
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.time: float = 0
        self.timer_0 = Timer(x=(self.board.left_offset + 32
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.timer_1 = Timer(x=(self.board.left_offset + 64
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.timer_2 = Timer(x=(self.board.left_offset + 96
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.timer = [self.timer_0, self.timer_1, self.timer_2]
        self.score_0 = Timer(x=(self.board.left_offset - 128
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.score_1 = Timer(x=(self.board.left_offset - 96
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.score_2 = Timer(x=(self.board.left_offset - 64
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.score = [self.score_0, self.score_1, self.score_2]
        self.score[0].number = (self.bombs // 100)
        self.score[1].number = ((self.bombs % 100) // 10)
        self.score[2].number = (self.bombs % 10)
        self.button_test = Button(self.board.left_offset - 125,
                                  self.board.top_offset,
                                  100, 50)
        self.button_1 = Button(self.board.left_offset - 125,
                               self.board.top_offset + 55,
                               100, 50)
        self.button_2 = Button(self.board.left_offset - 125,
                               self.board.top_offset + 110,
                               100, 50)
        self.button_3 = Button(self.board.left_offset - 125,
                               self.board.top_offset + 165,
                               100, 50)
        self.first_move = True
        self.play_sound = True
        self.new_highscore = True
        self.jr_reveal = jr_reveal

    def run(self) -> None:
        pg.init()
        pg.mixer.init()

        pg.display.set_caption("pysweeper")
        pg.display.set_icon(pg.image.load(load_file("textures/icon.png")))
        pg.display.set_mode(size=(32*self.width + 2*self.board.left_offset,
                                  32*self.height + 2*self.board.top_offset),
                            flags=pg.RESIZABLE,
                            vsync=True)

        ###
        import pygame_gui as pgui

        manager = pgui.UIManager((32*self.width + 2*self.board.left_offset,
                                  32*self.height + 2*self.board.top_offset))

        hello_button = pgui.elements.UIButton(relative_rect=pg.Rect((self.board.left_offset - 125, self.board.top_offset + 220), (-1, 50)),
                                              text="Hello World",
                                              manager=manager,
                                              object_id=pgui.core.ObjectID(class_id="@friendly_buttons",
                                              object_id="#hello_button"))
        ###

        clock = pg.time.Clock()

        if sys_name == "Windows":
            temp = win32gui.GetPixel(dc, 0, 0)

        input_arr = []
        cheat = False

        font = pg.font.Font(load_file("fonts/minecraft_regular.ttf"), 32)

        while True:
            screen.fill((170, 170, 170))

            self.board.draw()
            self.smiley.draw(screen)
            for timer in self.timer:
                timer.draw(screen)
            for score in self.score:
                score.draw(screen)

            mouse_pos = pg.mouse.get_pos()
            mouse_x = (mouse_pos[0] - self.board.left_offset) // 32
            mouse_y = (mouse_pos[1] - self.board.top_offset) // 32

            if cheat and sys_name == "Windows" and \
               mouse_x < self.width and mouse_x >= 0 and \
               mouse_y < self.height and mouse_y >= 0 and \
               not self.board.board[mouse_y][mouse_x].is_bomb:
                win32gui.SetPixel(dc, 0, 0, white)
            elif sys_name == "Windows":
                win32gui.SetPixel(dc, 0, 0, temp)

            for event in pg.event.get():
                if event.type == pg.QUIT:
                    pg.quit()
                    exit()

                if event.type == pg.MOUSEBUTTONDOWN:
                    self.smiley.set_in_awe()
                    if self.button_test.is_mouse_over(mouse_pos) and \
                       event.button == 1:
                        self.button_test.button_clicked = 1

                if event.type == pg.MOUSEBUTTONUP:
                    self.smiley.set_reset()
                    if mouse_x < self.width and \
                       mouse_x >= 0 and \
                       mouse_y < self.height and \
                       mouse_y >= 0 and \
                       self.board.game_over is None:
                        block = self.board.board[mouse_y][mouse_x]
                        if event.button == 1 and not block.is_revealed \
                           and not block.is_flagged:
                            pg.mixer.music.load(load_file("sounds/plop.mp3"))
                            pg.mixer.music.play()
                            self.clicks += 1
                            if self.first_move:
                                if block.is_bomb:
                                    self.board.move_bomb(mouse_x, mouse_y)
                                self.first_move = False
                            self.board.reveal(mouse_x, mouse_y)
                        elif event.button == 1 and block.is_revealed \
                                and self.jr_reveal:
                            pg.mixer.music.load(load_file("sounds/plop.mp3"))
                            pg.mixer.music.play()
                            self.clicks += 1
                            for i, j in itertools.product(range(-1, 2), range(-1, 2)):
                                if (
                                    0 <= mouse_x + i < self.width
                                    and 0 <= mouse_y + j < self.height
                                    and not self.board.board[mouse_y + j][mouse_x + i].is_revealed
                                    and not self.board.board[mouse_y + j][mouse_x + i].is_flagged
                                ):
                                    self.board.reveal(mouse_x + i, mouse_y + j)
                        elif event.button == 3 and not block.is_revealed:
                            if block.is_flagged:
                                self.flags -= 1
                                block.is_flagged = False
                            else:
                                self.flags += 1
                                block.is_flagged = True
                            self.update_score()
                        elif event.button == 2:
                            if not block.is_flagged:
                                if block.is_question_mark:
                                    self.question_marks -= 1
                                    block.is_question_mark = False
                                else:
                                    self.question_marks += 1
                                    block.is_question_mark = True
                    if mouse_pos[0] < self.smiley.get_position()[0] + 64 and \
                       mouse_pos[0] >= self.smiley.get_position()[0] and \
                       mouse_pos[1] < self.smiley.get_position()[1] + 64 and \
                       mouse_pos[1] >= self.smiley.get_position()[1] and \
                       event.button == 1:
                        self.restart()

                    if self.button_test.is_mouse_over(mouse_pos) and \
                       event.button == 1:
                        self.button_test.button_clicked = 0
                        # self.button_test.button_clicked = clock.get_fps()//20

                        # horrible practice, but at least
                        # it'll stop the game from crashing
                        # FIX THIS LATER
                        try:
                            input_arr.extend(str(read_json(prompt_file(load_file("icon.ico") if sys_name == "Windows" else None))))
                        except Exception as e:
                            print(e)

                    if self.button_1.is_mouse_over(mouse_pos) and \
                       event.button == 1:
                        self.button_1.button_clicked = int(clock.get_fps()//20)
                        input_arr.append('1')

                    if self.button_2.is_mouse_over(mouse_pos) and \
                       event.button == 1:
                        self.button_2.button_clicked = int(clock.get_fps()//20)
                        input_arr.append('2')

                    if self.button_3.is_mouse_over(mouse_pos) and \
                       event.button == 1:
                        self.button_3.button_clicked = int(clock.get_fps()//20)
                        input_arr.append('3')

                if event.type == pg.KEYDOWN:
                    if event.key in (pg.K_LSHIFT, pg.K_RSHIFT):
                        input_arr.append("shift")
                    elif (event.key == pg.K_BACKSPACE and
                          len(input_arr) > 0):
                        input_arr.pop()
                    else:
                        input_arr.append(event.unicode)
                    if len(input_arr) > 7 and \
                       input_arr[-8] == 'x' and input_arr[-7] == 'y' and \
                       input_arr[-6] == 'z' and input_arr[-5] == 'z' and \
                       input_arr[-4] == 'y' and input_arr[-3] == "shift" and \
                       input_arr[-2] == '\r' and input_arr[-1] == '\r':
                        cheat = not cheat
                        input_arr = []

                if event.type == pg.VIDEORESIZE:
                    # disallow resizing to smaller
                    # dimensions than the board size
                    self.screen = pg.display.set_mode((max(event.w, self.width*32),
                                                       max(event.h, self.height*32)),
                                                      pg.RESIZABLE)
                    self.resize()

                ###
                if event.type == pgui.UI_BUTTON_PRESSED:
                    if event.ui_element == hello_button:
                        input_arr.extend("Hello World!")

                manager.process_events(event)
                ###

            text = font.render("".join(input_arr), True, (0, 0, 0))
            screen.blit(text, (self.board.left_offset - 125, self.board.top_offset + self.board.height*32 + 50))

            self.board.check_win()

            if self.board.game_over == "WIN":
                self.smiley.set_cool()
                if self.new_highscore:
                    highscores = read_json(load_file("data/data.json"))
                    score_id = len(highscores)
                    summary = {
                        "width": self.width,
                        "height": self.height,
                        "bombs": self.bombs,
                        "clicks": self.clicks,
                        "time": round(self.time, 3)
                    }
                    highscores[score_id] = summary
                    write_json(load_file("data/data.json"), highscores)
                    self.new_highscore = False

            if self.board.game_over == "LOSE":
                if self.play_sound:
                    pg.mixer.music.load(load_file("sounds/explosion.mp3"))
                    pg.mixer.music.play()
                    self.play_sound = False
                self.smiley.set_dead()

            if self.board.game_over is None and not self.first_move:
                self.time += 1/60
                self.timer[0].number = (int(self.time) // 100)
                self.timer[1].number = ((int(self.time) % 100) // 10)
                self.timer[2].number = (int(self.time) % 10)

            if self.button_test.button_clicked > 0:
                self.button_test.draw(screen, "test",
                                      (0, 0, 0), (255, 255, 255),
                                      font)
                # self.button_test.button_clicked -= 1
            else:
                self.button_test.draw(screen, "test",
                                      (255, 255, 255), (0, 0, 0),
                                      font)

            if self.button_1.button_clicked > 0:
                self.button_1.draw(screen, '1',
                                   (0, 0, 0), (255, 255, 255),
                                   font)
                self.button_1.button_clicked -= 1
            else:
                self.button_1.draw(screen, '1',
                                   (255, 255, 255), (0, 0, 0),
                                   font)

            if self.button_2.button_clicked > 0:
                self.button_2.draw(screen, '2',
                                   (0, 0, 0), (255, 255, 255),
                                   font)
                self.button_2.button_clicked -= 1
            else:
                self.button_2.draw(screen, '2',
                                   (255, 255, 255), (0, 0, 0),
                                   font)

            if self.button_3.button_clicked > 0:
                self.button_3.draw(screen, '3',
                                   (0, 0, 0), (255, 255, 255),
                                   font)
                self.button_3.button_clicked -= 1
            else:
                self.button_3.draw(screen, '3',
                                   (255, 255, 255), (0, 0, 0),
                                   font)

            # clock.tick(60)

            ###
            pg.display.set_caption(f"pysweeper {clock.get_fps():.2f}")

            time_delta = clock.tick(60)/1000.0
            manager.update(time_delta)

            manager.draw_ui(screen)
            ###

            pg.display.update()

    def restart(self) -> None:
        self.clicks = 0
        self.flags = 0
        self.question_marks = 0
        temp_left_offset = self.board.left_offset
        temp_top_offset = self.board.top_offset
        self.board = Board(self.width, self.height, self.bombs)
        self.board.left_offset = temp_left_offset
        self.board.top_offset = temp_top_offset
        self.board.window_resize()
        self.smiley = Smiley(x=(self.board.left_offset - 32
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.time = 0
        self.set_digit_displays()
        self.score[0].number = (self.bombs // 100)
        self.score[1].number = ((self.bombs % 100) // 10)
        self.score[2].number = (self.bombs % 10)
        self.first_move = True
        self.new_highscore = True
        self.play_sound = True

    def resize(self) -> None:
        self.board.left_offset = (pg.display.get_surface().get_width() -
                                  32*self.width)//2
        self.board.top_offset = (pg.display.get_surface().get_height() -
                                 32*self.height)//2
        self.smiley = Smiley(x=(self.board.left_offset - 32
                                + 32*self.width//2),
                             y=(self.board.top_offset - 64))
        self.button_test.set_position(self.board.left_offset - 125, self.board.top_offset)
        self.button_1.set_position(self.board.left_offset - 125, self.board.top_offset + 55)
        self.button_2.set_position(self.board.left_offset - 125, self.board.top_offset + 110)
        self.button_3.set_position(self.board.left_offset - 125, self.board.top_offset + 165)
        self.set_digit_displays()
        self.update_score()
        self.board.window_resize()

    def set_digit_displays(self):
        self.timer_0 = Timer(x=(self.board.left_offset
                                + 32 + 32 * self.width // 2),
                             y=self.board.top_offset - 64)

        self.timer_1 = Timer(x=(self.board.left_offset
                                + 64 + 32 * self.width // 2),
                             y=self.board.top_offset - 64)

        self.timer_2 = Timer(x=(self.board.left_offset
                                + 96 + 32 * self.width // 2),
                             y=self.board.top_offset - 64)
        self.timer = [self.timer_0, self.timer_1, self.timer_2]

        self.score_0 = Timer(x=(self.board.left_offset
                                - 128 + 32 * self.width // 2),
                             y=self.board.top_offset - 64)

        self.score_1 = Timer(x=(self.board.left_offset
                                - 96 + 32 * self.width // 2),
                             y=self.board.top_offset - 64)

        self.score_2 = Timer(x=(self.board.left_offset
                                - 64 + 32 * self.width // 2),
                             y=self.board.top_offset - 64)
        self.score = [self.score_0, self.score_1, self.score_2]

    def update_score(self):
        self.score[0].number = ((((self.bombs - self.flags)) // 100))
        self.score[1].number = (((((self.bombs - self.flags)) % 100) // 10))
        self.score[2].number = ((((self.bombs - self.flags)) % 10))


def main() -> None:
    pass


if __name__ == "__main__":
    main()