#include "FastLED.h"
#include <Midier.h>

#define COMMON_TIME(x) (4 * (x))

// Matrix size
#define LED_ROWS 32
#define LED_COLS 32
#define NUM_LEDS LED_ROWS * LED_COLS
// LEDs pin
#define DATA_PIN 3
// LED brightness
#define BRIGHTNESS 255
// Define the array of leds
CRGB leds[NUM_LEDS];

int posX=random(0,(LED_COLS-1)*10);
int posY=random(0,(LED_ROWS-1)*10);
int aimX=random(0,(LED_COLS-1)*10);
int aimY=random(0,(LED_ROWS-1)*10);
uint8_t speedX =map(LED_COLS,8,32,2,10);
uint8_t speedY =map(LED_ROWS,8,32,2,10);

void drawPixelXYF(float x, float y, CRGB color)
{
 // if (x < 0 || y < 0 || x > ((float)WIDTH - 1) || y > ((float)HEIGHT - 1)) return;
  uint8_t xx = (x - (int)x) * 255, yy = (y - (int)y) * 255, ix = 255 - xx, iy = 255 - yy;
  // calculate the intensities for each affected pixel
  #define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8))
  uint8_t wu[4] = {WU_WEIGHT(ix, iy), WU_WEIGHT(xx, iy),
                   WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)};
  // multiply the intensities by the colour, and saturating-add them to the pixels
  for (uint8_t i = 0; i < 4; i++) {
    int16_t xn = x + (i & 1), yn = y + ((i >> 1) & 1);
    CRGB clr = leds[XY(xn, yn)];
    clr.r = qadd8(clr.r, (color.r * wu[i]) >> 8);
    clr.g = qadd8(clr.g, (color.g * wu[i]) >> 8);
    clr.b = qadd8(clr.b, (color.b * wu[i]) >> 8);
    leds[XY(xn, yn)] = clr;
  }
}

void aimchange(){
aimX=random(0,(LED_COLS-1)*10);
aimY=random(0,(LED_ROWS-1)*10);
leds[XY(aimX/10,aimY/10)] = CHSV(0,0,255);
}

void draw() {
  //fadeToBlackBy(leds, NUM_LEDS, beatsin8(2,1,10));
  blur2d(leds, LED_COLS, LED_ROWS, 120);
  if(round(posX/10)>round(aimX/10)){ posX-=speedX;}
  if(round(posY/10)>round(aimY/10)){ posY-=speedY;}
  if(round(posX/10)<round(aimX/10)){ posX+=speedX;}
  if(round(posY/10)<round(aimY/10)){ posY+=speedY;}
  if(round(posX/10)==round(aimX/10) && round(posY/10)==round(aimY/10)){aimchange();} 
  drawPixelXYF((float)posX/10,(float)posY/10, CHSV(40,255,255));
}

const midier::Config config = {
  .note       = midier::Note::A,
  .accidental = midier::Accidental::Natural,
  .octave     = 3,
  .mode       = midier::Mode::Ionian,
  .rhythm     = midier::Rhythm::Swung_Triplet,
  .steps      = 4, // play the 7th degree as well
  .perm       = 0,
  .looped     = true,
};

// create a container for one layer as only a single
// layer will be played at a time and use the custom configuration
midier::Layers<1> layers;

// create a sequencer from the layers container and specify BPM of 120
midier::Sequencer sequencer(layers, config, 120);

void setup() {
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  Serial.begin(9600);
  sequencer.start(1);
}

void loop() {
  sequencer.click(midier::Sequencer::Run::Async);
  draw();
  sequencer.click(midier::Sequencer::Run::Async);
  FastLED.show();
} //loop


uint16_t XY (uint8_t x, uint8_t y) {
  return (y * LED_COLS + x);
}