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

pygame.init()

width = 600
height = 900
clear_display = "0"
display_num_whole = clear_display
old_display_num_whole = display_num_whole
display_num_decimal = ""
old_display_num_decimal = display_num_decimal
num_float = False
float_precision = 1
yellow = (240, 240, 20)
white = (255, 255, 255)
black = (0, 0, 0)

button_origin_x = 90
button_origin_y = 280
button_spacing = 140

@dataclass
class Button:
    row: int
    column: int
    label: str
    key: int
    is_number: bool = False
    flashing: bool = False
    unflash_on: float = 0.0

keypad_map = {
    str(pygame.K_KP_0): pygame.K_0,
    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,
    str(pygame.K_KP_MINUS): pygame.K_MINUS,
    str(pygame.K_KP_MULTIPLY): pygame.K_MINUS,
    str(pygame.K_KP_DIVIDE): pygame.K_SLASH,
    str(pygame.K_KP_PLUS): pygame.K_PLUS,
    str(pygame.K_KP_PERIOD): pygame.K_PERIOD,
    str(pygame.K_KP_ENTER): pygame.K_EQUALS,
    str(pygame.K_RETURN): pygame.K_EQUALS
}
valid_keys_numbers = [
    pygame.K_0,
    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,
    pygame.K_KP_0,
    pygame.K_KP_1,
    pygame.K_KP_2,
    pygame.K_KP_3,
    pygame.K_KP_4,
    pygame.K_KP_5,
    pygame.K_KP_6,
    pygame.K_KP_7,
    pygame.K_KP_8,
    pygame.K_KP_9
]

valid_keys_equals = [
    pygame.K_EQUALS,
    pygame.K_RETURN,
    pygame.K_KP_ENTER
]

buttons = {
    str(pygame.K_0): Button(3, 1, "0", pygame.K_0, True),
    str(pygame.K_1): Button(2, 0, "1", pygame.K_1, True),
    str(pygame.K_2): Button(2, 1, "2", pygame.K_2, True),
    str(pygame.K_3): Button(2, 2, "3", pygame.K_3, True),
    str(pygame.K_4): Button(1, 0, "4", pygame.K_4, True),
    str(pygame.K_5): Button(1, 1, "5", pygame.K_5, True),
    str(pygame.K_6): Button(1, 2, "6", pygame.K_6, True),
    str(pygame.K_7): Button(0, 0, "7", pygame.K_7, True),
    str(pygame.K_8): Button(0, 1, "8", pygame.K_8, True),
    str(pygame.K_9): Button(0, 2, "9", pygame.K_9, True),
    str(pygame.K_PERIOD): Button(3, 2, ".", pygame.K_PERIOD),
    str(pygame.K_QUESTION): Button(3, 0, "+-", pygame.K_QUESTION),
    str(pygame.K_BACKSPACE): Button(0, 3, "<-", pygame.K_BACKSPACE),
    str(pygame.K_a): Button(1, 3, "AC", pygame.K_a),
    str(pygame.K_c): Button(2, 3, "C", pygame.K_c),
    str(pygame.K_EQUALS): Button(3, 3, "=", pygame.K_EQUALS),
    str(pygame.K_ASTERISK): Button(4, 3, "*", pygame.K_ASTERISK),
    str(pygame.K_PLUS): Button(4, 0, "+", pygame.K_PLUS),
    str(pygame.K_MINUS): Button(4, 1, "-", pygame.K_MINUS),
    str(pygame.K_SLASH): Button(4, 2, chr(247), pygame.K_SLASH)
}

def flash_button(b):
    if b.flashing == False:
        center_x = button_origin_x + (b.column * button_spacing)
        center_y = button_origin_y + (b.row * button_spacing)
        center = (center_x, center_y)
        pygame.draw.circle(screen, white, center, 50, 4)
        b.flashing = True
        b.unflash_on = time.time() + 0.1
    else:
        center_x = button_origin_x + (b.column * button_spacing)
        center_y = button_origin_y + (b.row * button_spacing)
        center = (center_x, center_y)
        pygame.draw.circle(screen, black, center, 50, 4)
        pygame.draw.circle(screen, yellow, center, 50, 2)
        b.flashing = False

def draw_buttons():

    for key, b in buttons.items():
        center_x = button_origin_x + (b.column * button_spacing)
        center_y = button_origin_y + (b.row * button_spacing)
        center = (center_x, center_y)
        pygame.draw.circle(screen, yellow, center, 50, 2)
        b_text = cheesy_font.render(b.label, True, white)
        text_x = center_x - (b_text.get_width() // 2)
        text_y = center_y - (b_text.get_height() // 2)
        if b.label == "*":
            text_y += 15
        screen.blit(b_text, (text_x, text_y))

screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('CheesyCalc')
icon = pygame.image.load(os.path.join("img", "cheesy_icon_32x32.png"))
icon.convert_alpha()
pygame.display.set_icon(icon)
logo = pygame.image.load(os.path.join("img", "cheesy.png"))
logo.convert_alpha()
screen.blit(logo, (30, 20))
cheesy_font = pygame.font.Font(os.path.join("font", "New Cheese.ttf"), 60)
logo_text_1 = cheesy_font.render("Cheesy", True, yellow)
logo_text_2 = cheesy_font.render("Calculator", True, yellow)
screen.blit(logo_text_1, (width // 2 - logo_text_1.get_width() // 2 + 80, 0))
screen.blit(logo_text_2, (width // 2 - logo_text_2.get_width() // 2 + 80, 45))
sevenseg_font = pygame.font.Font(os.path.join("font", "DSEG7Modern-Bold.ttf"), 60)
draw_buttons()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            pygame.quit()
            sys.exit()
        #elif event.type == pygame.KEYDOWN:
        #    print(event.key)
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_c:
            display_num_whole = clear_display
            display_num_decimal = ""
            num_float = False
            float_precision = 1
            flash_button(buttons[str(event.key)])
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_a:
            display_num_whole = clear_display
            display_num_decimal = ""
            num_float = False
            float_precision = 1
            flash_button(buttons[str(event.key)])
        elif event.type == pygame.KEYDOWN and (event.key == pygame.K_PERIOD or event.key == pygame.K_KP_PERIOD):
            actual_key = pygame.K_PERIOD
            flash_button(buttons[str(actual_key)])
            num_float = True
        elif event.type == pygame.KEYDOWN and event.key in valid_keys_equals and not pygame.key.get_mods() & pygame.KMOD_SHIFT:
            actual_key = pygame.K_EQUALS
            flash_button(buttons[str(actual_key)])
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_BACKSPACE:
            flash_button(buttons[str(event.key)])
            if num_float == True:
                if display_num_decimal == "":
                    num_float = False
                    if len(display_num_whole) > 1:
                        display_num_whole = display_num_whole[:-1]
                    elif display_num_whole != "0":
                        display_num_whole = "0"
                else:
                    display_num_decimal = display_num_decimal[:-1]
            else:
                if len(display_num_whole) > 1:
                    display_num_whole = display_num_whole[:-1]
                elif display_num_whole != "0":
                    display_num_whole = "0"
        elif event.type == pygame.KEYDOWN and ((event.key == pygame.K_EQUALS and pygame.key.get_mods() & pygame.KMOD_SHIFT) or event.key == pygame.K_KP_PLUS):
            actual_key = pygame.K_PLUS
            flash_button(buttons[str(actual_key)])
        elif event.type == pygame.KEYDOWN and (event.key == pygame.K_MINUS or event.key == pygame.K_KP_MINUS):
            actual_key = pygame.K_MINUS
            flash_button(buttons[str(actual_key)])
        elif event.type == pygame.KEYDOWN and ((event.key == pygame.K_8 and pygame.key.get_mods() & pygame.KMOD_SHIFT) or event.key == pygame.K_KP_MULTIPLY):
            actual_key = pygame.K_ASTERISK
            flash_button(buttons[str(actual_key)])
        elif event.type == pygame.KEYDOWN and (event.key == pygame.K_SLASH or event.key == pygame.K_KP_DIVIDE):
            actual_key = pygame.K_SLASH
            flash_button(buttons[str(actual_key)])
        elif event.type == pygame.KEYDOWN and event.key in valid_keys_numbers:
            if str(event.key) in keypad_map.keys():
                actual_key = keypad_map[str(event.key)]
            else:
                actual_key = event.key
            flash_button(buttons[str(actual_key)])
            if len(display_num_whole) <= 10:
                if num_float == False:
                    if display_num_whole == clear_display and actual_key != pygame.K_0:
                        display_num_whole = chr(actual_key)
                    elif display_num_whole != clear_display:
                        display_num_whole += chr(actual_key)
                else:
                    display_num_decimal += chr(actual_key)
    if display_num_whole != old_display_num_whole or display_num_decimal != old_display_num_decimal:
        print(f"Number: {display_num_whole}", end='')
        if num_float == True:
            print(".", end='')
        print(display_num_decimal)
        old_display_num_whole = display_num_whole
        old_display_num_decimal = display_num_decimal
    pygame.draw.rect(screen, (0, 0, 0), pygame.Rect(12, 97, 576, 126))
    num_show = (num_float == False) 
    text = sevenseg_font.render(display_num_whole + "." + display_num_decimal, True, white)
    screen.blit(text, (580 - text.get_width(), 120))
    pygame.draw.rect(screen, yellow, pygame.Rect(10, 100, 580, 110), 2)
    for key, b in buttons.items():
        if b.flashing == True and time.time() >= b.unflash_on:
            flash_button(b)
    pygame.display.flip()