from dataclasses import dataclass
from datetime import datetime
import math
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
import pygame
import sys
import time

@dataclass
class Button:
    row: int
    column: int
    key: int
    label: str
    sound_file: str
    center_x: int = 0
    center_y: int = 0
    flashing: bool = False
    unflash_on: float = 0.0

# Define buttons and their associated keyboard keys
BUTTONS = {
    str(pygame.K_1): Button(2, 0, pygame.K_1, "1", "8bit-fail.ogg"),
    str(pygame.K_2): Button(2, 1, pygame.K_2, "2", "brass-fail-8.ogg"),
    str(pygame.K_3): Button(2, 2, pygame.K_3, "3", "brass-fail-11.ogg"),
    str(pygame.K_4): Button(1, 0, pygame.K_4, "4", "error.ogg"),
    str(pygame.K_5): Button(1, 1, pygame.K_5, "5", "fail-1.ogg"),
    str(pygame.K_6): Button(1, 2, pygame.K_6, "6", "game-over.ogg"),
    str(pygame.K_7): Button(0, 0, pygame.K_7, "7", "invalid.ogg"),
    str(pygame.K_8): Button(0, 1, pygame.K_8, "8", "wah-wah.ogg"),
    str(pygame.K_9): Button(0, 2, pygame.K_9, "9", "wrong.ogg")
}

# Map number-pad numbers to normal keyboard numbers for simplicity
KEYPAD_MAP = {
    str(pygame.K_KP_1): pygame.K_1,
    str(pygame.K_KP_2): pygame.K_2,
    str(pygame.K_KP_3): pygame.K_3,
    str(pygame.K_KP_4): pygame.K_4,
    str(pygame.K_KP_5): pygame.K_5,
    str(pygame.K_KP_6): pygame.K_6,
    str(pygame.K_KP_7): pygame.K_7,
    str(pygame.K_KP_8): pygame.K_8,
    str(pygame.K_KP_9): pygame.K_9
}

# The valid keyboard keys that represent numbers for buttons
VALID_KEYS_NUMBERS = [
    pygame.K_1,
    pygame.K_2,
    pygame.K_3,
    pygame.K_4,
    pygame.K_5,
    pygame.K_6,
    pygame.K_7,
    pygame.K_8,
    pygame.K_9
]

# Some program globals
WIDTH = 1000
HEIGHT = 975
BACKGROUND_COLOR = (150, 150, 150)
LABEL_COLOR = (255, 255, 255)
LABEL_COLOR_FLASH = (0, 0, 0)

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Epic Fail Sound Board')
icon = pygame.image.load(os.path.join("img", "fail-icon.png"))
icon.convert_alpha()
pygame.display.set_icon(icon)
screen.fill(BACKGROUND_COLOR)
pygame.display.flip()
logo = pygame.image.load(os.path.join("img", "fail.png"))
logo.convert_alpha()
screen.blit(logo, ((WIDTH // 2) - (logo.get_width() // 2), 20))
button_origin_x = 100
button_origin_y = logo.get_height() + 20 + 25
button_img = pygame.image.load(os.path.join("img", "button-red.png"))
button_img.convert_alpha()
cheesy_font = pygame.font.Font(os.path.join("font", "New Cheese.ttf"), 60)
for b in BUTTONS.values():
    x = button_origin_x + ((button_img.get_width() + 100) * b.column)
    y = button_origin_y + ((button_img.get_height() + 30) * b.row)
    b.center_x = x + (button_img.get_width() // 2)
    b.center_y = y + (button_img.get_height() // 2)
    screen.blit(button_img, (x, y))
    b_text = cheesy_font.render(b.label, True, LABEL_COLOR)
    text_x = x + (button_img.get_width() // 2) - (b_text.get_width() // 2)
    text_y = y + (button_img.get_height() // 2) - (b_text.get_height() // 2)
    screen.blit(b_text, (text_x, text_y))
pygame.display.flip()

# This function processes a button press/activation
#    1) Flash the button
#    2) Play the sound
def do_button(key):
    for b in BUTTONS.values():
        if b.key == key:
            audio = pygame.mixer.Sound(os.path.join("snd", b.sound_file))
            flash_button(b)
            audio.play()

def flash_button(b: Button):
    if b.flashing == False:
        text_color = LABEL_COLOR_FLASH
        b.flashing = True
        b.unflash_on = time.time() + 0.1
    else:
        text_color = LABEL_COLOR
        b.flashing = False
    b_text = cheesy_font.render(b.label, True, text_color)
    text_x = b.center_x - (b_text.get_width() // 2)
    text_y = b.center_y - (b_text.get_height() // 2)
    screen.blit(b_text, (text_x, text_y))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        mouse_click = None
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            for b in BUTTONS.values():
                if math.hypot(mouse_x - b.center_x, mouse_y - b.center_y) <= (button_img.get_width() // 2):
                    mouse_click = b.key
        if event.type == pygame.KEYDOWN or not mouse_click is None:
            if mouse_click is None:
                my_key = KEYPAD_MAP[str(event.key)] if str(event.key) in KEYPAD_MAP.keys() else event.key
            else:
                my_key = mouse_click
            if my_key == pygame.K_ESCAPE:
                pygame.quit()
                sys.exit()
            elif my_key in VALID_KEYS_NUMBERS:
                do_button(my_key)
    for b in BUTTONS.values():
        if b.flashing == True and time.time() >= b.unflash_on:
            flash_button(b)
    pygame.display.flip()