import math

import pygame
import serial

import time
import colorsys

from util import clamp, rescale
from fixtures import MovingHead

if __name__ == "__main__":

    movingheads = [
        MovingHead(1),
        MovingHead(15),
        MovingHead(29),
        MovingHead(43),
    ]

    # movingheads[0].rgbw = (59, 130, 246, 0)  # blue
    # movingheads[1].rgbw = (245, 158, 11, 0)  # yellow
    # movingheads[2].rgbw = (239, 68, 68, 0)  # red
    # movingheads[3].rgbw = (16, 185, 129, 0)  # green

    for head in movingheads:
        head.rgbw = (0, 0, 0xFF, 0)

    for head in movingheads:
        head.pan = -0.5 * math.pi

    dmx_data = bytearray(512)

    # pygame initialization

    pygame.init()  # pylint: disable=no-member; wtf?

    screen = pygame.display.set_mode((420, 69), pygame.RESIZABLE)
    pygame.display.set_caption("meh")

    pygame.joystick.init()
    gamepad = pygame.joystick.Joystick(0)
    gamepad.init()

    clock = pygame.time.Clock()

    # main loop

    running = True  # this is clearly not constant, see 17 lines below???

    with serial.Serial("/dev/ttyUSB0", 500_000) as ser:

        def sync():
            # wait for sync
            while True:
                b = ser.readline()
                if b.strip() == b"Sync.":
                    return

        sync()

        while running:

            for event in pygame.event.get():
                if event.type == pygame.QUIT:  # pylint: disable=no-member;
                    running = False

            # axes:
            pitch = gamepad.get_axis(4)  # 0 horizontal, -1 up, 1 down
            whammy = gamepad.get_axis(3)  # -1 default, 1 if max. pressed

            # buttons:
            button_state = [
                gamepad.get_button(i)
                for i in [
                    0,  # green
                    1,  # red
                    3,  # yellow
                    2,  # blue
                    4,  # orange
                ]
            ]

            # strumm bar
            (_, bar) = gamepad.get_hat(0)

            print(
                f"pitch: {pitch:+0.2f}, "
                f"whammy: {whammy:+0.2f}, "
                f"buttons: {button_state}, "
                f"bar: {bar: 1}"
            )

            # render

            for head_id, button_id in enumerate([3, 2, 1, 0]):
                movingheads[head_id].dimmer = 0 if button_state[button_id] else 1

            pitch = max(0, min(1, -1 * pitch))  # 0 horizontal, 1 up
            tilt = rescale(pitch, (0, 1), (-0.5 * math.pi, 0))
            for head in movingheads:
                head.tilt = tilt
                r, g, b = colorsys.hls_to_rgb((time.time() / 12) % 1, 0.5, 1)
                head.rgbw = (int(255 * r), int(255 * g), int(255 * b), 0)

            ANGLE_HOME = -0.5 * math.pi
            ANGLE_OUTER = 0.5235988
            ANGLE_INNER = 0.2617994

            movingheads[0].pan = rescale(
                whammy, (-1, 1), (ANGLE_HOME, ANGLE_HOME + ANGLE_OUTER)
            )
            movingheads[1].pan = rescale(
                whammy, (-1, 1), (ANGLE_HOME, ANGLE_HOME + ANGLE_INNER)
            )
            movingheads[2].pan = rescale(
                whammy, (-1, 1), (ANGLE_HOME, ANGLE_HOME - ANGLE_INNER)
            )
            movingheads[3].pan = rescale(
                whammy, (-1, 1), (ANGLE_HOME, ANGLE_HOME - ANGLE_OUTER)
            )

            for head in movingheads:
                # print(head)
                head.render(dmx_data)

            ser.write(dmx_data)
            ser.flush()
            response = ser.readline()
            if response.strip() != b"Ack.":
                print(f"received bad response: {response!r}")
                sync()

            try:
                clock.tick(50)
            except KeyboardInterrupt:
                running = False

    pygame.quit()  # pylint: disable=no-member;
