from random import randint

from kmk.keys import make_argumented_key
from kmk.modules import Module


class RapidFireMeta:
    def __init__(
        self,
        kc,
        interval=100,
        timeout=200,
        enable_interval_randomization=False,
        randomization_magnitude=15,
        toggle=False,
    ):
        self.kc = kc
        self.interval = interval
        self.timeout = timeout
        self.enable_interval_randomization = enable_interval_randomization
        self.randomization_magnitude = randomization_magnitude
        self.toggle = toggle


class RapidFire(Module):
    _active_keys = {}
    _toggled_keys = []
    _waiting_keys = []

    def __init__(self):
        make_argumented_key(
            validator=RapidFireMeta,
            names=('RF',),
            on_press=self._rf_pressed,
            on_release=self._rf_released,
        )

    def _get_repeat(self, key):
        if key.meta.enable_interval_randomization:
            return key.meta.interval + randint(
                -key.meta.randomization_magnitude, key.meta.randomization_magnitude
            )
        return key.meta.interval

    def _on_timer_timeout(self, key, keyboard):
        keyboard.tap_key(key.meta.kc)
        if key in self._waiting_keys:
            self._waiting_keys.remove(key)
        if key.meta.toggle and key not in self._toggled_keys:
            self._toggled_keys.append(key)
        self._active_keys[key] = keyboard.set_timeout(
            self._get_repeat(key), lambda: self._on_timer_timeout(key, keyboard)
        )

    def _rf_pressed(self, key, keyboard, *args, **kwargs):
        if key in self._toggled_keys:
            self._toggled_keys.remove(key)
            self._deactivate_key(key, keyboard)
            return
        if key.meta.timeout > 0:
            keyboard.tap_key(key.meta.kc)
            self._waiting_keys.append(key)
            self._active_keys[key] = keyboard.set_timeout(
                key.meta.timeout, lambda: self._on_timer_timeout(key, keyboard)
            )
        else:
            self._on_timer_timeout(key, keyboard)

    def _rf_released(self, key, keyboard, *args, **kwargs):
        if key not in self._active_keys:
            return
        if key in self._toggled_keys:
            if key not in self._waiting_keys:
                return
            self._toggled_keys.remove(key)
        if key in self._waiting_keys:
            self._waiting_keys.remove(key)
        self._deactivate_key(key, keyboard)

    def _deactivate_key(self, key, keyboard):
        keyboard.cancel_timeout(self._active_keys[key])
        self._active_keys.pop(key)

    def during_bootup(self, keyboard):
        return

    def before_matrix_scan(self, keyboard):
        return

    def before_hid_send(self, keyboard):
        return

    def after_hid_send(self, keyboard):
        return

    def on_powersave_enable(self, keyboard):
        return

    def on_powersave_disable(self, keyboard):
        return

    def after_matrix_scan(self, keyboard):
        return