import buttons  # TODO
import display
import leds
from color import Color

import utime
import urandom


# TODO: https://www.rdocumentation.org/packages/base/versions/3.6.1/topics/seq
def seq(start, stop, step=1):
    n = int(round((stop - start)/float(step)))

    if n > 1:
        return([start + step*i for i in range(n+1)])
    elif n == 1:
        return([start])
    else:
        return([])


# TODO: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
def randomize(arr, n):
    # Start from the last element and swap one by one. We don't
    # need to run for the first element that's why i > 0
    for i in range(n-1, 0, -1):
        # Pick a random index from 0 to i
        j = urandom.randint(0, i+1)

        # Swap arr[i] with the element at random index
        arr[i], arr[j] = arr[j], arr[i]
    return arr


class stroboscope:
    # TODO: add full RGB spectrum, check against previously selected color
    purple15 = [Color(230, 230, 250), Color(216, 191, 216), Color(221, 160, 221),
                Color(238, 130, 238), Color(218, 112, 214), Color(255, 0, 255),
                Color(255, 0, 255), Color(186, 85, 211), Color(147, 112, 219),
                Color(138, 43, 226), Color(148, 0, 211), Color(153, 50, 204),
                Color(139, 0, 139), Color(128, 0, 128), Color(75, 0, 130)]

    yellow11 = [Color(255, 228, 181), Color(255, 218, 185), Color(238, 232, 170),
                Color(240, 230, 140), Color(189, 183, 107), Color(255, 255, 0),
                Color(128, 128, 0), Color(173, 255, 47), Color(154, 205, 50),
                Color(255, 255, 102), Color(255, 255, 51)]

    def __init__(self, delay, matrix, width, random=False,
                 rocket=False, top_bar=False, top_width=1):
        # TODO: implement LED brightness
        if len(self.purple15) % width != 0:
            raise ValueError
        if len(self.yellow11) % top_width != 0:
            raise ValueError
        if len(matrix) != 4:
            raise ValueError

        self.color_random = random
        self.color_width = width
        self.led_delay = delay
        self.led_matrix = matrix

        self.rocket = rocket
        self.top_bar = top_bar
        self.top_width = top_width

    def begin(self):
        # TODO: process button events
        self.color_range = seq(0, len(self.purple15)-1, self.color_width)
        self.top_range = seq(0, len(self.yellow11)-1, self.top_width)
        self.rocket_on = False

        while True:
            r = urandom.randint(0, 255)
            g = urandom.randint(0, 255)
            b = urandom.randint(0, 255)

            with display.open() as disp:
                disp.clear([r, g, b]).update()

            if self.color_random is True:
                try:
                    self.color_range = randomize(
                        self.color_range, len(self.purple15))
                    self.top_range = randomize(
                        self.top_range, len(self.yellow11))
                except IndexError:
                    # FIXME: index out of range errors in index swap (L26)
                    print("bug: sequence shuffle failed (out of range)")

            # TODO: set amount of used top leds "width"
            for k, i in enumerate(self.top_range):  # TODO: check self.top_bar
                leds.prep(k, self.yellow11[i])

            for i in self.color_range:
                if self.led_matrix[0] == 1:
                    leds.prep(leds.TOP_LEFT, self.purple15[i])
                if self.led_matrix[1] == 1:
                    leds.prep(leds.TOP_RIGHT, self.purple15[i])
                if self.led_matrix[2] == 1:
                    leds.prep(leds.BOTTOM_LEFT, self.purple15[i])
                if self.led_matrix[3] == 1:
                    leds.prep(leds.BOTTOM_RIGHT, self.purple15[i])

                leds.update()

                if self.rocket is False:
                    continue
                if self.rocket_on is True:
                    leds.set_rocket(0, 31)  # TODO: define brightness
                    leds.set_rocket(1, 31)
                    leds.set_rocket(2, 31)
                else:
                    leds.set_rocket(0, 0)
                    leds.set_rocket(1, 0)
                    leds.set_rocket(2, 0)
                self.rocket_on = not self.rocket_on

            # main LED delay
            utime.sleep_ms(self.led_delay)


def main():
    Strobo = stroboscope(100, [1, 1, 1, 1], 1, True, True, 1)
    Strobo.begin()


if __name__ == "__main__":
    main()