#include <Arduino.h>
#include <FastLED.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

#define PIR_SAMPLE_TIME 100 // 100ms
#define TIMEOUT_MAX 10000 // 30s
#define SECOND 1000 // 1s

#define ON 1
#define OFF 0

  int fade_speed = 0;
// Pins:
#define DATA_PIN 4


// How many leds in your strip?
#define NUM_LEDS 3

// Delay between each fade step
#define FADE_DELAY 10

CRGB leds[NUM_LEDS];

int ledPin = 13;                // choose the pin for the LED
int inputPin = 2;               // choose the input pin (for PIR sensor)
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;                    // variable for reading the pin status
int pir_pin = 2;

int timeoutCountDown = 0;

enum system_state_enum {

    SYSTEM_STATE_IDLE, //LED OFF

    SYSTEM_STATE_ACTIVE, // LED ON when idle is triggered

    SYSTEM_STATE_TIMEOUT, // Counting down from time out to 0 then goes to IDLE

    SYSTEM_STATE_ERROR

};


int prev_pir_val = 0; // variable for storing the last pin status

//unsigned long prev_millis = 0; // variable for storing the last time the PIR sensor was triggered

unsigned long prev_tm0  = 0;
unsigned long prev_tm1 = 0;



void led_switch(int ledPin, int ledState) {

    switch (ledState) {

        case ON:

            digitalWrite(ledPin, HIGH);  // turn LED ON

            Serial.println("LED ON");

            break;

        case OFF:

            digitalWrite(ledPin, LOW);  // turn LED OFF

            Serial.println("LED OFF");

            break;

    }

}


/* void doFade(int fade_speed) {
  static int level = 0;
  EVERY_N_MILLIS(FADE_DELAY) {
    level += fade_speed;
    if (level < 0)   level = 0;
    if (level > 255) level = 255;
    fill_solid(leds, NUM_LEDS, CHSV(255, 255, level));
    FastLED.show();
  }
}
 */
void doFade(int fade_speed) {

  static int level = 0;
  static unsigned long prev_millis = 0;
  unsigned long currentMillis = millis();

    if (currentMillis - prev_millis >= FADE_DELAY) {

        level += fade_speed;

        if (level < 0)   level = 0;

        if (level > 255) level = 255;

        fill_solid(leds, NUM_LEDS, CHSV(255, 255, level));

        FastLED.show();

        prev_millis = currentMillis;

    }

}


/*   EVERY_N_MILLIS(FADE_DELAY) {
    level += fade_speed;
    if (level < 0)   level = 0;
    if (level > 255) level = 255;
    fill_solid(leds, NUM_LEDS, CHSV(255, 255, level));
    FastLED.show();
  }
} */


void timeout_timer() {





}

void system_state_machine() {

    int read_pir_state = LOW;
    static unsigned long  prev_millis = 0;


    switch (pirState) {

        case SYSTEM_STATE_IDLE:

            read_pir_state = digitalRead(pir_pin);

            if (read_pir_state == HIGH) {

                pirState = SYSTEM_STATE_ACTIVE;

                Serial.println("Motion detected! IDLE -> ACTIVE");

            }


            break;

        case SYSTEM_STATE_ACTIVE:

              read_pir_state = digitalRead(pir_pin);
            
                timeoutCountDown = TIMEOUT_MAX;
          //   digitalWrite(ledPin, HIGH);  // turn LED ON


            // Transitio to Timeout State

            pirState = SYSTEM_STATE_TIMEOUT;

            Serial.println("Transition SYSTEM_STATE_ACTIVE -> SYSTEM_STATE_TIMEOUT");

            led_switch(ledPin, ON);

            address_led(ON);

             // Fade in
            fade_speed = 1;

          //  doFade(fade_speed);
         
            break;

        case SYSTEM_STATE_TIMEOUT:

            // Every second while still in timeout, decrement the timeout counter
            // If motion is detected, reset the timeout counter

            {
                unsigned long current_millis = millis(); // get the current time

            int read_pir_state = digitalRead(pir_pin);

            switch (read_pir_state) {

                case HIGH: // Motion detected

                    timeoutCountDown = TIMEOUT_MAX;

                    Serial.println("Motion detected! Resetting timeout counter");

                    break;

                case LOW:

                  //  timeoutCountDown -= (current_millis - prev_millis);

                  //  Serial.println("Timeout Count Down: " + String(timeoutCountDown));

                    break;

            }

            if (current_millis - prev_millis > SECOND) {


                if (timeoutCountDown > 0) {

                    timeoutCountDown -= SECOND;



                    Serial.println("Timeout Count Down: " + String(timeoutCountDown));

                } else if (timeoutCountDown <= 0) {

                    // Transition to Idle State

                    pirState = SYSTEM_STATE_IDLE;

                    Serial.println("Transition SYSTEM_STATE_TIMEOUT -> SYSTEM_STATE_IDLE");

                    led_switch(ledPin, OFF);

                    address_led(OFF);


                      // Fade out
     
                }


                prev_millis = current_millis;

            }


            }
            break;

        case SYSTEM_STATE_ERROR:

            break;

    }


}


void timer_0() {
 
unsigned long current_millis = millis(); // get the current time

  if (current_millis - prev_tm0 > 300UL) {


      system_state_machine();


    prev_tm0 = current_millis;
  }

}


void address_led(int led_state) {

    switch (led_state) {

        case ON:
            fill_solid(leds, NUM_LEDS, CHSV(255, 255, 255));
            FastLED.show();
          break;

        case OFF:   

            fill_solid(leds, NUM_LEDS, CHSV(255, 255, 0));
            FastLED.show();
            break;

    }

}

void setup() {
  // put your setup code here, to run once:
    pinMode(ledPin, OUTPUT);      // declare LED as output
  pinMode(inputPin, INPUT);     // declare sensor as input
    FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);  // GRB ordering is assumed

    int i;

  for(i=0;i<NUM_LEDS;i++)
  {
    leds[i] = CRGB::White;
  }
FastLED.show();

  Serial.begin(115200);


}

void loop() {
  // put your main code here, to run repeatedly:

//system_state_machine();



//doFade(fade_speed);
/*
   PIR sensor tester
*/
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
neopixel1:VDD
neopixel1:DOUT
neopixel1:VSS
neopixel1:DIN
neopixel2:VDD
neopixel2:DOUT
neopixel2:VSS
neopixel2:DIN
neopixel3:VDD
neopixel3:DOUT
neopixel3:VSS
neopixel3:DIN
pir1:VCC
pir1:OUT
pir1:GND
led1:A
led1:C
pir2:VCC
pir2:OUT
pir2:GND
pir3:VCC
pir3:OUT
pir3:GND
rgb1:VDD
rgb1:DOUT
rgb1:VSS
rgb1:DIN
rgb2:VDD
rgb2:DOUT
rgb2:VSS
rgb2:DIN