from absled import ILedString
from num_utils import color_hex_to_tuple


def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        return 0, 0, 0
    if pos < 85:
        return 255 - pos * 3, pos * 3, 0
    if pos < 170:
        pos -= 85
        return 0, 255 - pos * 3, pos * 3
    pos -= 170
    return pos * 3, 0, 255 - pos * 3


class ILedPatternMeta(type):
    """
    Metaclass for the ILedPattern interface
    """
    def __instancecheck__(cls, instance):
        return cls.__subclasscheck__(type(instance))

    def __subclasscheck__(cls, subclass):
        return hasattr(subclass, 'tick') and callable(subclass.tick)

class ILedPattern:
    """
    Interface for an LED pattern
    """
    def __init__(self, config: dict, leds: ILedString):
        self.config = config
        self.leds = leds

    def tick(self):
        pass

class SolidColorPattern(ILedPattern):
    def __init__(self, config: dict, leds: ILedString):
        super().__init__(config, leds)
        self.color = color_hex_to_tuple(config.get("color", "#ffffff"))

    def tick(self):
        self.leds.fill_leds(self.color)
        self.leds.show()

class RainbowPattern(ILedPattern):
    def __init__(self, config: dict, leds: ILedString):
        super().__init__(config, leds)
        self.j = 0

    def tick(self):
        if self.j >= 255:
            self.j = 0
        for i in range(self.leds.num_leds):
            rc_index = (i * 256 // self.leds.num_leds) + self.j
            self.leds.set_led(wheel(rc_index & 255), i)
        self.leds.show()
        self.j += 1
