from dataclasses import dataclass
from enum import Enum, auto
from datetime import time, datetime
from typing import Optional, Any
from time import sleep
from pynput import keyboard
from pynput.keyboard import Key, Controller

# Simple Alarm Clock has 5 functionalities:
# 1. Set Alarm Time - Set the time for the alarm to sound, does NOT make the alarm active
# 2. Start Alarm    - Make the alarm active, which will run the timer until it reaches the specified time
# 3. Sound Alarm    - Play the sound for the alarm
# 4. Snooze Alarm   - Stop the alarm sound and wait for some time to play the alarm again
# 5. Stop Alarm     - If the alarm is active or is playing, stop the alarm (deactivate state)

ALARM_TIME = time(19, 13, 0)
SNOOZE_SEC = 5
SNOOZE_KEY = keyboard.Key.up
ALARM_OFF_KEY = keyboard.Key.esc


class AlarmState(Enum):
    SET = auto(),
    RUNNING = auto(),
    PLAYING = auto(),
    SNOOZED = auto(),
    DEACTIVATED = auto(),


@dataclass
class BaseAlarmClock:
    # player: Optional
    wake_time: time
    current_state: AlarmState = AlarmState.DEACTIVATED

    def set_alarm(self, wake_time: time) -> time:
        print(f"SETTING ALARM to: {wake_time}")
        self.current_state = AlarmState.SET
        self.wake_time = wake_time
        return self.wake_time

    def start_alarm(self, check_frequency: int = 1):
        print("STARTING ALARM")
        self.current_state = AlarmState.RUNNING
        # now = datetime.now().time()
        # if now >= self.wake_time:
        #     return False
        # sleep_time_amount = max(check_frequency, 1)
        # while now < self.wake_time:
        #     # Sleep for some time
        #     sleep(sleep_time_amount)
        #     now = datetime.now().time()
        # self.sound_alarm()
        # return True

    def sound_alarm(self):
        print("SOUNDING ALARM")
        self.current_state = AlarmState.PLAYING
        # if sound is not None:
        #     self.player.set_media(sound)
        # self.player.audio_set_volume(volume)
        # self.player.play()

    def snooze_alarm(self, snooze_time: int = SNOOZE_SEC):
        print("SNOOZING ALARM")
        self.current_state = AlarmState.SNOOZED
        # self.player.pause()
        # Maybe make this async later
        sleep(snooze_time)
        # self.player.play()
        if self.current_state is AlarmState.SNOOZED:
            self.sound_alarm()

    def stop_alarm(self, deactivate: bool = True):
        print("STOPPING ALARM")
        if self.current_state is AlarmState.PLAYING:
            print("STOPPED PLAYING ALARM")
            # self.player.stop()
        self.current_state = AlarmState.DEACTIVATED if deactivate else AlarmState.SET

    def alarm_check_reached(self, current_time = datetime.now().time()) -> bool:
        result = current_time >= self.wake_time if self.current_state is AlarmState.RUNNING else False
        print(f"{result = }")
        return result


def simple_alarm_mode(alarm_time):
    alarm_clock = BaseAlarmClock(alarm_time)
    alarm_clock.start_alarm()
    while not alarm_clock.alarm_check_reached():
        print(f"ALARM SLEEPING @: {datetime.now().time()}")
        sleep(1)
    alarm_clock.sound_alarm()
    while alarm_clock.current_state is not AlarmState.DEACTIVATED:
        with keyboard.Events() as events:
            for event in events:
                if event.key == ALARM_OFF_KEY:
                    alarm_clock.stop_alarm()
                    break
                elif event.key == SNOOZE_KEY:
                    alarm_clock.snooze_alarm()
                    break


if __name__ == '__main__':
    simple_alarm_mode(ALARM_TIME)