import math

from kmk.event_defs import (hid_report_event, keycode_down_event,
                            keycode_up_event)
from kmk.keycodes import Media
from kmk.rotary_encoder import RotaryEncoder

VAL_FALSE = False + 1
VAL_NONE = True + 2
VAL_TRUE = True + 1
VOL_UP_PRESS = keycode_down_event(Media.KC_AUDIO_VOL_UP)
VOL_UP_RELEASE = keycode_up_event(Media.KC_AUDIO_VOL_UP)
VOL_DOWN_PRESS = keycode_down_event(Media.KC_AUDIO_VOL_DOWN)
VOL_DOWN_RELEASE = keycode_up_event(Media.KC_AUDIO_VOL_DOWN)


class RotaryEncoderMacro:
    def __init__(self, pos_pin, neg_pin, slop_history=1, slop_threshold=1):
        self.encoder = RotaryEncoder(pos_pin, neg_pin)
        self.max_history = slop_history
        self.history = bytearray(slop_history)
        self.history_idx = 0
        self.history_threshold = math.floor(slop_threshold * slop_history)

    def scan(self):
        # Anti-slop logic
        self.history[self.history_idx] = 0

        reading = self.encoder.direction()
        self.history[self.history_idx] = VAL_NONE if reading is None else reading + 1

        self.history_idx += 1

        if self.history_idx >= self.max_history:
            self.history_idx = 0

        nones = 0
        trues = 0
        falses = 0

        for val in self.history:
            if val == VAL_NONE:
                nones += 1
            elif val == VAL_TRUE:
                trues += 1
            elif val == VAL_FALSE:
                falses += 1

        if nones >= self.history_threshold:
            return None

        if trues >= self.history_threshold:
            return self.on_increase()

        if falses >= self.history_threshold:
            return self.on_decrease()

    def on_decrease(self):
        pass

    def on_increase(self):
        pass


class VolumeRotaryEncoder(RotaryEncoderMacro):
    def on_decrease(self):
        yield VOL_DOWN_PRESS
        yield hid_report_event
        yield VOL_DOWN_RELEASE
        yield hid_report_event

    def on_increase(self):
        yield VOL_UP_PRESS
        yield hid_report_event
        yield VOL_UP_RELEASE
        yield hid_report_event