class NetRadioAlarmClock():
    def __init__(self):
        self.queue = Queue()
        self.alarm_running_queue = Queue()
        self.media = MultimmediaController()
        self.sched = Scheduler()
        self.tts = TextToSpeech()
        self.schedule = {}
        #self.gcal = GoogleCalendar()
        self.arduino = ArduinoController(0x08, self.queue)
        self.gpio = RPiGPIO()
        self.radio_db = RadioDB(
            "/home/pi/Python/NetRadioAlarmClockPi/radio-settings.db")
        self.webserver = webserver
        self.webserver.add_station_cb = self.add_station
        self.webserver.get_stations_cb = self.radio_db.get_stations
        self.webserver.set_current_station_cb = self.set_current_station
        self.webserver.get_current_station_cb = self.get_current_station
        self.webserver.update_station_name_cb = self.radio_db.update_station_title
        self.webserver.get_stream_playing_cb = self.media.get_playing
        self.webserver.play_stream_cb = self.start_stream
        self.webserver.stop_stream_cb = self.stop_stream
        self.webserver.set_volume_cb = self.media.set_volume
        self.webserver.get_schedule_cb = self.get_schedule
        self.webserver.save_schedule_cb = self.save_schedule
        self.webserver.alarm_running_queue = self.alarm_running_queue
        self.alarm_running = False
        self.update_interval = 60 * 5
        self.state = "idle"
        self.gpio.set_snooze_btn_callback(self.alarm_snooze_event)
        self.webdev = False
        self.stream_playing = False
        self.alarm_running_queue.put(False)
        self.last_snooze_time = None
        self.button_press_count = 0
        self.debouncing = False

        # Set current station
        url, station_title = self.get_current_station()
        self.media.set_stream_url(url)

        # Load radio alarm schedule and set up events if there are any
        self.load_schedule()
        self.create_events()

        # Test event
        test_time = datetime.datetime(2021, 2, 23, 20, 14, 0)
        self.sched.add_event(test_time, self.alarm_event)

        if len(sys.argv) > 1:
            #print(sys.argv)
            if sys.argv[1].replace("\r", "") == "webdev":
                print("Web development mode")
                self.webdev = True

        if not self.webdev:
            print("Resetting Arduino")
            self.gpio.reset_arduino()
            print("Done")

            self.arduino.set_vol_change_callback(self.media.set_volume)
            self.arduino.start_rot_enc_thread()

    # Set current station from web interface
    def set_current_station(self, station_url):
        self.radio_db.set_current_station(station_url)
        self.media.set_stream_url(station_url)

    def add_station(self, station_url):
        title = self.media.get_title_from_any_url(station_url)
        self.radio_db.add_station(station_url, title)

    def get_current_station(self):
        station_url = self.radio_db.get_current_station()
        title = self.radio_db.get_title_for_station_url(station_url)
        return station_url, title

    def test_radio(self):
        self.media.set_stream_url(radio_triplej_url)
        self.media.play_stream()

    def test_alarm(self):
        pass

    def start_stream(self, queue):
        self.media.play_stream()
        self.stream_playing = True
        queue.put(True)
        volume = self.media.get_volume()
        url, station_name = self.get_current_station()
        if not self.webdev:
            self.update_lcd_playing("null")
        self.webserver.emit_status(self.stream_playing, volume, station_name)

    def stop_stream(self, queue):
        self.media.stop_stream()
        self.stream_playing = False
        queue.put(False)
        volume = self.media.get_volume()
        url, station_name = self.get_current_station()
        webserver.emit_status(self.stream_playing, volume, station_name)

    def setup(self):
        #print("Station: " + self.mpdc.get_station_name())
        #print("Artist: " + self.mpdc.get_artist())
        #print("Title: " + self.mpdc.get_title())

        if not self.webdev:
            #time.sleep(5)
            # display idle screen
            print("Updating arduino idle (with time)")
            self.arduino.update_lcd_idle()

            # read events from google calendar
            #self.update_events("null")
            #self.media.set_stream_url(radio_triplej_url)

            # Testing
            #self.test_radio()
            #self.alarm_event(datetime.datetime.now())
            pass

        # update time on arduino
        #self.update_lcd_idle("null")

    def get_schedule(self):
        events = self.radio_db.get_events()
        cur_time = datetime.datetime.now()
        schedule = {
            "weekday_time": "",
            "enabled_weekdays": [],
            "weekend_time": "",
            "enabled_weekend_days": [],
            "next_alarm": ""
        }
        for event in events:
            e_time = datetime.datetime.strptime(event, "%Y-%m-%d %H:%M:%S")
            if (e_time - cur_time).hours < 24:
                schedule["next_alarm"] = event
            if e_time.weekday() >= 0 and e_time.weekday() < 5:
                schedule["weekday_time"] = event
            if e_time.weekday() >= 5 and e_time.weekday() < 7:
                schedule["weekend_time"] = event
            if e_time.weekday() == 0:
                schedule["enabled_weekdays"].append("monday")
            if e_time.weekday() == 1:
                schedule["enabled_weekdays"].append("tuesday")
            if e_time.weekday() == 2:
                schedule["enabled_weekdays"].append("wednesday")
            if e_time.weekday() == 3:
                schedule["enabled_weekdays"].append("thursday")
            if e_time.weekday() == 4:
                schedule["enabled_weekdays"].append("friday")
            if e_time.weekday() == 5:
                schedule["enabled_weekend_days"].append("saturday")
            if e_time.weekday() == 6:
                schedule["enabled_weekend_days"].append("sunday")

    def save_schedule(self, schedule):
        print("Saving new schedule?")
        self.schedule = schedule
        self.radio_db.save_schedule(schedule)
        self.create_events()

    def load_schedule(self):
        self.schedule = self.radio_db.load_schedule()
        self.webserver.saved_schedule = self.schedule
        print("Saved schedule: " + str(self.schedule))

    def create_events(self):
        days = [
            "monday", "tuesday", "wednesday", "thursday", "friday", "saturday",
            "sunday"
        ]
        if self.schedule is None:
            return
        enabled_weekdays = self.schedule["enabled_weekdays"]
        enabled_weekend_days = self.schedule["enabled_weekend_days"]
        weekday_time = datetime.datetime.strptime(
            self.schedule["weekday_time"], "%H:%M")
        weekend_time = datetime.datetime.strptime(
            self.schedule["weekend_time"], "%H:%M")

        def get_day_integer(day_str):
            for i in range(0, len(days)):
                day_i_str = days[i]
                if day_i_str == day_str:
                    return i
            print("ERROR: No day for : '" + day_str + "'")
            return -1

        self.sched.remove_all_events()

        for day in enabled_weekdays:
            day_int = get_day_integer(day)
            if day_int >= 0:
                print("Adding alarm for day: " + days[day_int])
                self.sched.add_weekday_event_day(day_int, weekday_time,
                                                 self.alarm_event)
            else:
                print("ERROR: weekday int not found for '" + day + "', " +
                      str(day_int))

        for day in enabled_weekend_days:
            day_int = get_day_integer(day)
            if day_int > 0:
                print("Adding alarm for weekend day: " + days[day_int])
                self.sched.add_weekday_event_day(day_int, weekend_time,
                                                 self.alarm_event)
            else:
                print("ERROR: weekend day int not found for '" + day + "'")

    def add_events_new(self, events, cb_func):
        self.radio_db.clear_events()
        self.sched.remove_all_events()
        for event in events:
            self.radio_db.add_event(event["time"])
            self.sched.add_event(event["time"], cb_func)

    def update_lcd_playing(self, time_str):
        #station = self.mpdc.get_station_name()
        #artist = self.mpdc.get_artist()
        #title = self.mpdc.get_title()

        station = self.media.get_station_title()
        #print("station: " + station)

        self.arduino.update_lcd_playing(station, "", "")
        #one_second = datetime.datetime.now() + datetime.timedelta(seconds=1)
        #if self.state == "playing":
        #    self.sched.schedule_event(one_second, self.update_lcd_playing)

    def update_lcd_idle(self):
        self.arduino.update_lcd_idle()
        #one_second = datetime.datetime.now() + datetime.timedelta(seconds=1)

        #if self.state == "idle":
        #    self.sched.schedule_event(one_second, self.update_lcd_idle)
    def alarm_snooze_delay(self):
        # If button pressed only once - snoozing
        if self.button_press_count == 1:
            print("SNOOZING!! ZZZZ")
            now = datetime.datetime.now()
            h = str(now.hour)
            m = str(now.minute)
            if now.minute < 10:
                m = "0" + m
            text = "Snoozing. The time is now {hr} {min}".format(hr=h, min=m)
            self.tts.say(text)
            self.state = "snooze"
            self.media.stop_stream()
            self.alarm_running = False
            radio_rest_time = datetime.datetime.now() + datetime.timedelta(
                minutes=7)
            self.sched.add_event(radio_rest_time, self.alarm_event)
            self.alarm_running_queue.put(False)
            self.last_snooze_time = None
            self.button_press_count = 0
            if not self.webdev:
                self.update_lcd_idle()
        elif self.button_press_count > 1:
            print("Alarm OFF! Time to get up!!")
            self.tts.say("Alarm is now off. Time to get up!")
            self.alarm_running_queue.put(False)
            self.media.stop_stream()
            # Clear snooze event
            self.sched.remove_fixed_events()
            self.button_press_count = 0
        else:
            print("Button pressed more than once! I see that.. Alarm stop?")

    def debounce(self):
        self.debouncing = False
        print("Debounced?")

    def alarm_snooze_event(self, channel):
        if not self.debouncing:
            self.button_press_count += 1
            print("Btn count: " + str(self.button_press_count))
            if self.button_press_count == 1:
                self.last_snooze_time = datetime.datetime.now()
                # Check in three seconds if the button has been pressed more than once
                threading.Timer(3, self.alarm_snooze_delay).start()

            self.debouncing = True
            threading.Timer(0.2, self.debounce).start()
        else:
            print("Bounce!")

    def alarm_event(self):
        if self.state == "snooze":
            now = datetime.datetime.now()
            now_h = now.hour
            now_m = now.minute
            if self.last_snooze_time is not None:
                last_m = self.last_snooze_time.minute
                last_h = self.last_snooze_time.hour
                # If we snoozed in the same minute, don't alarm again (bit of a hack)
                if now_h == last_h and now_m == last_m:
                    return
        self.state = "playing"
        self.media.play_stream()
        self.alarm_running = True
        self.alarm_running_queue.put(True)
        if not self.webdev:
            self.update_lcd_playing("null")

    def run_alarm_button(self, queue):
        running = False
        while True:
            data = None
            if not queue.empty():
                data = queue.get()
            if data is True:
                running = True
            elif data is False:
                running = False
            self.sched.process_events()
            time.sleep(1)
            if running:
                #print("Running!")
                self.update_lcd_playing("null")
                self.gpio.snooze_button_led_on()
                time.sleep(0.5)
                self.gpio.snooze_button_lef_off()
                time.sleep(0.5)
            else:
                #print("idle")
                self.arduino.update_lcd_idle()
                time.sleep(4)

    def update_idle_thread(self, queue):
        #self.arduino = ArduinoController(0x08)
        idle = True
        while True:
            data = None
            if not queue.empty():
                data = queue.get()
            if data is False:
                idle = True
            elif data is True:
                idle = False
            if idle:
                #TODO: run main playing screen when playing
                print("Idling")
                self.arduino.update_lcd_idle()
                time.sleep(5)

    def run(self):
        alarm_btn_thread = threading.Thread(target=self.run_alarm_button,
                                            args=(self.alarm_running_queue, ))
        alarm_btn_thread.daemon = True
        alarm_btn_thread.start()
        #update_idle_thread = threading.Thread(target=self.update_idle_thread, args=(self.alarm_running_queue,))
        #update_idle_thread.daemon = True
        #update_idle_thread.start()
        #while True:
        #    time.sleep(1)
        print("Start web server?")
        self.webserver.run()