#include "ATALights.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include <Arduino.h>
#include "Animations.h"
#include <functional>
#include <NeoPixelBus.h>


static const char* tag = "strips";

// Define constants for maximum LEDs
#define MAX_LEDS 300 // Adjust based on your LED requirements

// Create pointers for NeoPixelBus objects
void* strip1 = nullptr;
void* strip2 = nullptr;

TaskHandle_t Animation_Task_Handle;

// Runtime configuration variables
int numLeds1 = 0, numLeds2 = 0;    // Number of LEDs for each strip
int dataPin1 = -1, dataPin2 = -1;  // Data pins for each strip
String chipType1, chipType2;       // Chip types (e.g., WS2812, SK6812, TM1814)
String colorOrder1, colorOrder2;   // Color orders (e.g., GRB, RGB, BGR)


void Init_Lights_Task(void){

	xTaskCreatePinnedToCore(Lights_Control_Task, "LumaMaster_Task", 1024*6, NULL, 1, &Animation_Task_Handle, CONFIG_ARDUINO_RUNNING_CORE);
	ESP_LOGI(tag, "Lights Task Created...");


    // Example runtime configuration for two strips
    dataPin1 = 5;          // Pin for Strip 1
    numLeds1 = 150;        // Number of LEDs on Strip 1
    chipType1 = "WS2812";  // Chip type for Strip 1
    colorOrder1 = "GRB";   // Color order for Strip 1

    dataPin2 = 18;         // Pin for Strip 2
    numLeds2 = 100;        // Number of LEDs on Strip 2
    chipType2 = "WS2812";  // Chip type for Strip 2
    colorOrder2 = "RGB";   // Color order for Strip 2

    // Dynamically initialize the strips
    strip1 = initializeStrip(dataPin1, numLeds1, chipType1, colorOrder1);
    strip2 = initializeStrip(dataPin2, numLeds2, chipType2, colorOrder2);


    // Start the strips if initialized
    if (strip1) static_cast<NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod>*>(strip1)->Begin();
    if (strip2) static_cast<NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod>*>(strip2)->Begin();
}


void Animation_Loop_Exit(void){
    if( Animation_Task_Handle ){ 
        xTaskNotifyGive( Animation_Task_Handle ); 
    }
}


void LightsON(void){
    FastLED.show();
}


void LightsOff(void){
    FastLED.clear();
    FastLED.show();
}



inline void setPixel1(int pixelIndex, const CRGB col) {
    register uint16_t x = pixelIndex + ledSettings[0].shift;
    // If strip.effSize is power of 2, use faster bit masking
    if ((ledSettings[0].effSize & (ledSettings[0].effSize - 1)) == 0) {
        x = (x < 0) ? ((x + ledSettings[0].effSize) & (ledSettings[0].effSize - 1)) : (x & (ledSettings[0].effSize - 1));
        leds1[(x + ledSettings[0].offset) & (ledSettings[0].effSize - 1)] = col;
    } else {
        // For non-power-of-2 sizes, still need modulo
        x = (x < 0) ? ((x + ledSettings[0].effSize) % ledSettings[0].effSize) : (x % ledSettings[0].effSize);
        leds1[(x + ledSettings[0].offset) % ledSettings[0].effSize] = col;
    }
}


inline void setPixel2(int pixelIndex, const CRGB col) {
    register uint16_t x = pixelIndex + ledSettings[1].shift;
    // If strip.effSize is power of 2, use faster bit masking
    if ((ledSettings[1].effSize & (ledSettings[1].effSize - 1)) == 0) {
        x = (x < 0) ? ((x + ledSettings[1].effSize) & (ledSettings[1].effSize - 1)) : (x & (ledSettings[1].effSize - 1));
        leds2[(x + ledSettings[1].offset) & (ledSettings[1].effSize - 1)] = col;
    } else {
        // For non-power-of-2 sizes, still need modulo
        x = (x < 0) ? ((x + ledSettings[1].effSize) % ledSettings[1].effSize) : (x % ledSettings[1].effSize);
        leds2[(x + ledSettings[1].offset) % ledSettings[1].effSize] = col;
    }
}


void Lights_Control_Task_Resume(void){
    vTaskResume(Animation_Task_Handle);
}

void Lights_Control_Task(void *parameters){

    ESP_LOGD(tag, "Lights Control Task Entered...");
    vTaskSuspend(NULL);
    ESP_LOGD(tag, "Lights Control Task Resumed...");
    vTaskDelay(2000);
    fill_solid(leds1, ledSettings[0].size-1, CRGB::Blue);
    FastLED.show();
    vTaskDelay(5000);

    while(true){
        Animation_Loop(2000, [&]()  {
            ESP_LOGD(tag, "Looping....");
            
            // Example animation: Alternate colors between strips
            setStripColor<NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod>>(strip1, numLeds1, RgbColor(255, 0, 0)); // Red for Strip 1
            setStripColor<NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod>>(strip2, numLeds2, RgbColor(0, 255, 0)); // Green for Strip 2
            delay(1000);

            setStripColor<NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod>>(strip1, numLeds1, RgbColor(0, 0, 255)); // Blue for Strip 1
            setStripColor<NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod>>(strip2, numLeds2, RgbColor(255, 255, 0)); // Yellow for Strip 2
            delay(1000);
        });

        /*
        uint8_t animMode = 1;
        switch(animMode){
            case 0:
                break;
            case 1: 
                break;
        }
        */
    }
}


void Init_FastLED_Strip(CRGB* leds, uint8_t pin, int size, EOrder rgbOrder, const String& chipType) {
    

    
}

// Function to initialize a strip dynamically (Non-SPI chipsets only)
void* initializeStrip(int dataPin, int numLeds, const String& chipType, const String& colorOrder) {
    if (chipType == "WS2812" || chipType == "SK6812") {
        if (colorOrder == "GRB") {
            return new NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod>(numLeds, dataPin);
        } else if (colorOrder == "RGB") {
            return new NeoPixelBus<NeoRgbFeature, Neo800KbpsMethod>(numLeds, dataPin);
        } else if (colorOrder == "BGR") {
            return new NeoPixelBus<NeoBgrFeature, Neo800KbpsMethod>(numLeds, dataPin);
        }
    }
    Serial.println("Unsupported chipset or color order!");
    return nullptr;
}

// Function to set all LEDs of a strip to a specific color
template <typename T>
void setStripColor(void* strip, int numLeds, RgbColor color) {
    if (strip) {
        T* actualStrip = static_cast<T*>(strip);
        for (int i = 0; i < numLeds; i++) {
            actualStrip->SetPixelColor(i, color);
        }
        actualStrip->Show();
    }
}


