import appglue
import badge
import time
import ugfx


def on_select(pressed):
    if pressed:
        if not sel.locked:
            sel.coarse = not sel.coarse
            sel.render_ui()
        sel.last_select_press = time.time()
    else:
        sel.last_select_press = 0

def on_start(pressed):
    if pressed and not sel.locked:
        badge.nvs_set_u8('led_col_sel', 'red', sel.red)
        badge.nvs_set_u8('led_col_sel', 'green', sel.green)
        badge.nvs_set_u8('led_col_sel', 'blue', sel.blue)
        badge.nvs_set_u8('led_col_sel', 'white', sel.white)
        badge.nvs_set_u8('led_col_sel', 'rgb_enabled', sel.rgb_enabled)
        badge.nvs_set_u8('led_col_sel', 'white_enabled', sel.white_enabled)
        badge.nvs_set_u8('led_col_sel', 'hsv_mode', sel.hsv_mode)
        appglue.home()

def on_a(pressed):
    if pressed and not sel.locked:
        sel.rgb_enabled = not sel.rgb_enabled
        sel.render_ui()

def on_b(pressed):
    if pressed and not sel.locked:
        sel.white_enabled = not sel.white_enabled
        sel.render_ui()

def on_up(pressed):
    if not sel.locked:
        if pressed:
            sel.selected_slider_index -= 1
            sel.selected_slider_index = max(sel.selected_slider_index, 0)
            sel.render_ui()
            sel.last_up_press = time.time()
        else:
            sel.last_up_press = 0

def on_down(pressed):
    if pressed and not sel.locked:
        sel.selected_slider_index += 1
        sel.selected_slider_index = min(sel.selected_slider_index, 3)
        sel.render_ui()

def on_left(pressed):
    if not sel.locked:
        sel.left_pressed = pressed

def on_right(pressed):
    if not sel.locked:
        sel.right_pressed = pressed


class LEDColorSelector:
    def __init__(self):
        self.red = 255
        self.green = 255
        self.blue = 255
        self.white = 255
        self.hue = 0
        self.saturation = 0
        self.value = 0
        self.selected_slider_index = 0
        self.coarse = True
        self.rgb_enabled = True
        self.white_enabled = True
        self.left_pressed = False
        self.right_pressed = False
        self.last_select_press = 0
        self.last_up_press = 0
        self.locked = False
        self.hsv_mode = False

    def render_slider(self, x, y, width, min, max, value, colour, fill):
        value_x = round((value-min)/(max-min) * width) + x
        if fill:
            ugfx.fill_rounded_box(x, y+2, width, 4, 0, colour)
        else:
            ugfx.box(x, y+2, width, 4, colour)
        ugfx.thickline(value_x, y, value_x, y+8, colour, 2, 0)

    def render_slider_with_label(self, x, y, width, min, max, value, label, colour, fill):
        ugfx.string_box(x, y, 40, 12, label, "Roboto_Regular12", ugfx.BLACK, ugfx.justifyLeft)
        self.render_slider(x+40, y+3, width, min, max, value, colour, fill)

    def render_ui(self):
        ugfx.clear(ugfx.WHITE)
        if self.hsv_mode:
            self.render_slider_with_label(0, 0, 80, 0, 359, self.hue, "Hue", ugfx.BLACK, (self.selected_slider_index == 0))
            self.render_slider_with_label(0, 20, 80, 0, 100, self.saturation, "Sat.", ugfx.BLACK, (self.selected_slider_index == 1))
            self.render_slider_with_label(0, 40, 80, 0, 100, self.value, "Value", ugfx.BLACK, (self.selected_slider_index == 2))
        else:
            self.render_slider_with_label(0, 0, 80, 0, 255, self.red, "Red", ugfx.BLACK, (self.selected_slider_index == 0))
            self.render_slider_with_label(0, 20, 80, 0, 255, self.green, "Green", ugfx.BLACK, (self.selected_slider_index == 1))
            self.render_slider_with_label(0, 40, 80, 0, 255, self.blue, "Blue", ugfx.BLACK, (self.selected_slider_index == 2))
        if self.hsv_mode:
            self.red, self.green, self.blue = map(round, self.hsv_to_rgb(self.hue, self.saturation, self.value))
        self.render_slider_with_label(0, 60, 80, 0, 255, self.white, "White", ugfx.BLACK, (self.selected_slider_index == 3))
        ugfx.string_box(0, 80, 128, 15, ("Mode: Coarse" if self.coarse else "Mode: Fine"), "Roboto_Regular12", ugfx.BLACK, ugfx.justifyCenter)
        ugfx.string_box(0, 95, 128, 15, ("RGB: Enabled" if self.rgb_enabled else "RGB: Disabled"), "Roboto_Regular12", ugfx.BLACK, ugfx.justifyCenter)
        ugfx.string_box(0, 110, 128, 15, ("White: Enabled" if self.white_enabled else "White: Disabled"), "Roboto_Regular12", ugfx.BLACK, ugfx.justifyCenter)
        if self.locked:
            ugfx.string_box(0, 125, 128, 15, "Buttons locked", "Roboto_Regular12", ugfx.BLACK, ugfx.justifyCenter)
        ugfx.string_box(0, 145, 128, 15, "Colour", "Roboto_Regular12", ugfx.BLACK, ugfx.justifyCenter)
        ugfx.string_box(0, 160, 128, 30, "#%02x%02x%02x" % (self.red, self.green, self.blue), "Roboto_Black22", ugfx.BLACK, ugfx.justifyCenter)
        ugfx.string_box(0, 186, 128, 110, "UP/DOWN: Select\n(Long press UP: HSV mode)\nLEFT/RIGHT: Modify\nA/B: Toggle RGB/White\nSELECT: Coarse/Fine\n(Long press: Btn lock)\nSTART: Exit", "pixelade13", ugfx.BLACK, ugfx.justifyCenter)
        ugfx.flush()
        red = self.red if self.rgb_enabled else 0
        green = self.green if self.rgb_enabled else 0
        blue = self.blue if self.rgb_enabled else 0
        white = self.white if self.white_enabled else 0
        self.set_led_colour((green, red, blue, white))

    def increment_current_slider(self):
        if self.hsv_mode:
            if self.selected_slider_index == 0:
                self.hue += 10 if self.coarse else 1
            elif self.selected_slider_index == 1:
                self.saturation += 10 if self.coarse else 1
            elif self.selected_slider_index == 2:
                self.value += 10 if self.coarse else 1
        else:
            if self.selected_slider_index == 0:
                self.red += 10 if self.coarse else 1
            elif self.selected_slider_index == 1:
                self.green += 10 if self.coarse else 1
            elif self.selected_slider_index == 2:
                self.blue += 10 if self.coarse else 1
        if self.selected_slider_index == 3:
            self.white += 10 if self.coarse else 1
        self.red = min(self.red, 255)
        self.green = min(self.green, 255)
        self.blue = min(self.blue, 255)
        self.hue = min(self.hue, 359)
        self.saturation = min(self.saturation, 100)
        self.value = min(self.value, 100)
        self.white = min(self.white, 255)

    def decrement_current_slider(self):
        if self.hsv_mode:
            if self.selected_slider_index == 0:
                self.hue -= 10 if self.coarse else 1
            elif self.selected_slider_index == 1:
                self.saturation -= 10 if self.coarse else 1
            elif self.selected_slider_index == 2:
                self.value -= 10 if self.coarse else 1
        else:
            if self.selected_slider_index == 0:
                self.red -= 10 if self.coarse else 1
            elif self.selected_slider_index == 1:
                self.green -= 10 if self.coarse else 1
            elif self.selected_slider_index == 2:
                self.blue -= 10 if self.coarse else 1
        if self.selected_slider_index == 3:
            self.white -= 10 if self.coarse else 1
        self.red = max(self.red, 0)
        self.green = max(self.green, 0)
        self.blue = max(self.blue, 0)
        self.hue = max(self.hue, 0)
        self.saturation = max(self.saturation, 0)
        self.value = max(self.value, 0)
        self.white = max(self.white, 0)

    def hsv_to_rgb(self, h, s, v):
        h /= 360.0
        s /= 100.0
        v /= 100.0
        if s == 0.0: v*=255; return (v, v, v)
        i = int(h*6.) # XXX assume int() truncates!
        f = (h*6.)-i; p,q,t = int(255*(v*(1.-s))), int(255*(v*(1.-s*f))), int(255*(v*(1.-s*(1.-f)))); v*=255; i%=6
        if i == 0: return (v, t, p)
        if i == 1: return (q, v, p)
        if i == 2: return (p, v, t)
        if i == 3: return (p, q, v)
        if i == 4: return (t, p, v)
        if i == 5: return (v, p, q)

    def rgb_to_hsv(self, r, g, b):
        r, g, b = r/255.0, g/255.0, b/255.0
        mx = max(r, g, b)
        mn = min(r, g, b)
        df = mx-mn
        if mx == mn:
            h = 0
        elif mx == r:
            h = (60 * ((g-b)/df) + 360) % 360
        elif mx == g:
            h = (60 * ((b-r)/df) + 120) % 360
        elif mx == b:
            h = (60 * ((r-g)/df) + 240) % 360
        if mx == 0:
            s = 0
        else:
            s = (df/mx)*100
        v = mx*100
        return h, s, v

    def set_led_colour(self, colour):
        # colour: [g, r, b, w]
        ledData = b""
        for i in range(6):
            ledData += bytes(colour)
        badge.leds_send_data(ledData)

    def run(self):
        ugfx.orientation(90)
        ugfx.set_lut(ugfx.LUT_FULL)
        ugfx.clear(ugfx.WHITE)
        ugfx.flush()
        ugfx.set_lut(ugfx.LUT_NORMAL)
        ugfx.input_attach(ugfx.BTN_SELECT, on_select)
        ugfx.input_attach(ugfx.BTN_START, on_start)
        ugfx.input_attach(ugfx.BTN_A, on_a)
        ugfx.input_attach(ugfx.BTN_B, on_b)
        ugfx.input_attach(ugfx.JOY_UP, on_up)
        ugfx.input_attach(ugfx.JOY_DOWN, on_down)
        ugfx.input_attach(ugfx.JOY_LEFT, on_left)
        ugfx.input_attach(ugfx.JOY_RIGHT, on_right)
        badge.leds_init()
        badge.leds_enable()

        self.red = badge.nvs_get_u8('led_col_sel', 'red', 255)
        self.green = badge.nvs_get_u8('led_col_sel', 'green', 255)
        self.blue = badge.nvs_get_u8('led_col_sel', 'blue', 255)
        self.white = badge.nvs_get_u8('led_col_sel', 'white', 255)
        self.rgb_enabled = badge.nvs_get_u8('led_col_sel', 'rgb_enabled', 1)
        self.white_enabled = badge.nvs_get_u8('led_col_sel', 'white_enabled', 1)
        self.hsv_mode = badge.nvs_get_u8('led_col_sel', 'hsv_mode', 0)
        
        if self.hsv_mode:
            self.hue, self.saturation, self.value = map(round, self.rgb_to_hsv(self.red, self.green, self.blue))

        self.render_ui()

        last_update = 0
        while True:
            if self.last_select_press != 0 and time.time() - self.last_select_press > 1:
                if not self.locked:
                    self.coarse = not self.coarse # Undo action caused by select press
                self.locked = not self.locked
                self.last_select_press = 0
                self.render_ui()
            if self.last_up_press != 0 and time.time() - self.last_up_press > 1:
                self.hsv_mode = not self.hsv_mode
                if self.hsv_mode:
                    self.hue, self.saturation, self.value = map(round, self.rgb_to_hsv(self.red, self.green, self.blue))
                else:
                    self.red, self.green, self.blue = map(round, self.hsv_to_rgb(self.hue, self.saturation, self.value))
                self.last_up_press = 0
                self.render_ui()
            if time.time() - last_update > 0.25:
                if self.left_pressed:
                    self.decrement_current_slider()
                    self.render_ui()
                elif self.right_pressed:
                    self.increment_current_slider()
                    self.render_ui()
                last_update = time.time()


sel = LEDColorSelector()
sel.run()