#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <INA226.h>
#include <ESP8266HTTPClient.h>

const int redPin = 12;   // Red
const int greenPin = 13; // Green
const int bluePin = 14;  // Blue

const int warning = 16;   
const int pwmResolution = 1024;

TwoWire Wire_; 

// INA226 instances
INA226 redINA(0x45, &Wire_);    // 1000101
INA226 blueINA(0x41, &Wire_);   // 1000100
INA226 greenINA(0x44, &Wire_);  // 1000001

const char *ssid = "dlink-AB48";
const char *password = "mjjbk74568";

// Array to store slave IP addresses
const char* slaveIPs[] = {
    "192.168.129.119",  // Slave 1
};
const int NUM_SLAVES = sizeof(slaveIPs) / sizeof(slaveIPs[0]);

int redValue = 0;
int greenValue = 0;
int blueValue = 0;
float brightness = 100.0;
bool rainbowActive = false;
unsigned long lastRainbowUpdate = 0;
int currentHue = 0;

// New variables for current monitoring
float redCurrent = 0;
float greenCurrent = 0;
float blueCurrent = 0;
unsigned long lastCurrentUpdate = 0;

ESP8266WebServer server(80);
WiFiClient wifiClient;


void handleSetRGB() {
    if (server.hasArg("r") && server.hasArg("g") && server.hasArg("b")) {
        redValue = server.arg("r").toInt();
        greenValue = server.arg("g").toInt();
        blueValue = server.arg("b").toInt();
        rainbowActive = false;

        // Set master LED
        setRGB(redValue, greenValue, blueValue, brightness);

        // Propagate to slaves
        String url = String("/set_rgb?r=") + redValue + 
                    String("&g=") + greenValue + 
                    String("&b=") + blueValue;
        propagateToSlaves(url);

        server.send(200, "text/plain", "RGB updated");
    } else {
        server.send(400, "text/plain", "Missing RGB arguments");
    }
}


// Modified handleSetBrightness to propagate to slaves
void handleSetBrightness() {
    if (server.hasArg("value")) {
        brightness = server.arg("value").toFloat();
        setRGB(redValue, greenValue, blueValue, brightness);

        // Propagate to slaves
        String url = String("/set_brightness?value=") + brightness;
        propagateToSlaves(url);

        server.send(200, "text/plain", "Brightness updated");
    } else {
        server.send(400, "text/plain", "Missing brightness argument");
    }
}

// Modified handleRainbow to propagate to slaves
void handleRainbow() {
    if (server.hasArg("state")) {
        rainbowActive = server.arg("state") == "true";
        if (!rainbowActive) {
            setRGB(redValue, greenValue, blueValue, brightness);
        }

        // Propagate to slaves
        String url = String("/rainbow?state=") + server.arg("state");
        propagateToSlaves(url);
    }
    server.send(200, "text/plain", rainbowActive ? "Rainbow started" : "Rainbow stopped");
}

// New function to propagate commands to slaves
void propagateToSlaves(String endpoint) {
    HTTPClient http;
    for (int i = 0; i < NUM_SLAVES; i++) {
        String url = String("http://") + slaveIPs[i] + endpoint;
        http.begin(wifiClient, url);
        int httpCode = http.GET();
        
        if (httpCode != HTTP_CODE_OK) {
            Serial.printf("Failed to propagate to slave %s: %d\n", slaveIPs[i], httpCode);
        }
        http.end();
    }
}

void handleGetCurrents() {
  String json = "{\"red\":" + String(redCurrent, 3) + 
                ",\"green\":" + String(greenCurrent, 3) + 
                ",\"blue\":" + String(blueCurrent, 3) + 
                ",\"total\":" + String(redCurrent + greenCurrent + blueCurrent, 3) + 
                ",\"redBusV\":" + String(redINA.getBusVoltage(), 3) + 
                ",\"greenBusV\":" + String(greenINA.getBusVoltage(), 3) + 
                ",\"blueBusV\":" + String(blueINA.getBusVoltage(), 3) + 
                "}";
  server.send(200, "application/json", json);
}

void scanI2CBus(TwoWire &wire) {
  Serial.println("Scanning I2C Bus...");
  for (uint8_t address = 1; address < 127; ++address) {
    wire.beginTransmission(address);
    if (wire.endTransmission() == 0) {
      Serial.print("Device found at address 0x");
      Serial.println(address, HEX);
    }
  }
}

void initializeINA226(INA226 &sensor, const char* name) {
    if (!sensor.begin()) {
        Serial.print("INA226 initialization failed for ");
        Serial.println(name);
    } else {
        Serial.print("INA226 initialized for ");
        Serial.println(name);
    }

    if (strcmp(name, "RED") == 0) {
        sensor.setMaxCurrentShunt(0.4, 0.09);
    } else if (strcmp(name, "GREEN") == 0) {
        sensor.setMaxCurrentShunt(0.35, 0.18);
    } else if (strcmp(name, "BLUE") == 0) {
        sensor.setMaxCurrentShunt(0.35, 0.18);
    } else {
        // Default case for unknown names
        sensor.setMaxCurrentShunt(0, 0); 
    }
}


void setup() {
  Serial.begin(115200);
  analogWriteRange(pwmResolution);
  Serial.println("Initializing RGB LED Controller with Current Monitoring");


  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  setRGB(redValue, greenValue, blueValue, brightness);

  delay(100);
  Wire_.begin(5, 4);
  delay(200);
  scanI2CBus(Wire_);
  delay(200);  // Extended delay
  initializeINA226(redINA, "RED");
  delay(200);
  initializeINA226(greenINA, "GREEN");
  delay(200);
  initializeINA226(blueINA, "BLUE");

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("Connected to Wi-Fi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/set_rgb", handleSetRGB);
  server.on("/set_brightness", handleSetBrightness);
  server.on("/rainbow", handleRainbow);
  server.on("/get_currents", handleGetCurrents);

  server.begin();
}

void loop() {
  server.handleClient();
  
  unsigned long currentMillis = millis();
  
  // Current measurement update (every 100ms)
  if (currentMillis - lastCurrentUpdate >= 100) {
    // Get current readings from all sensors
    redCurrent = redINA.getCurrent_mA();
    greenCurrent = greenINA.getCurrent_mA();
    blueCurrent = blueINA.getCurrent_mA();
    lastCurrentUpdate = currentMillis;
  }
  
  // Rainbow animation update (every 20ms)
  if (rainbowActive && (currentMillis - lastRainbowUpdate >= 20)) {
    float r, g, b;
    hsvToRgb(currentHue, 1.0, brightness / 100.0, r, g, b);
    setRGB((int)(r * 255), (int)(g * 255), (int)(b * 255), brightness);
    currentHue = (currentHue + 1) % 360;
    lastRainbowUpdate = currentMillis;
  }
}

void hsvToRgb(int hue, float saturation, float value, float &r, float &g, float &b) {
  float c = value * saturation;
  float x = c * (1 - abs(fmod(hue / 60.0, 2) - 1));
  float m = value - c;

  if (hue >= 0 && hue < 60) {
    r = c; g = x; b = 0;
  } else if (hue >= 60 && hue < 120) {
    r = x; g = c; b = 0;
  } else if (hue >= 120 && hue < 180) {
    r = 0; g = c; b = x;
  } else if (hue >= 180 && hue < 240) {
    r = 0; g = x; b = c;
  } else if (hue >= 240 && hue < 300) {
    r = x; g = 0; b = c;
  } else {
    r = c; g = 0; b = x;
  }

  r += m; g += m; b += m;
}

int mapDutyCycle(int value, float brightness) {
  float adjusted = value * (brightness / 100.0);
  return (int)(adjusted * pwmResolution / 255.0);
}

void setRGB(int red, int green, int blue, float brightness) {
  analogWrite(redPin, mapDutyCycle(red, brightness));
  analogWrite(greenPin, mapDutyCycle(green, brightness));
  analogWrite(bluePin, mapDutyCycle(blue, brightness));
}

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// [Previous ESP8266 setup code remains the same until handleRoot()]

void handleRoot() {
  String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <title>RGB Control</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue-color/2.8.1/vue-color.min.js"></script>
  <style>
    @import url(https://fonts.googleapis.com/css?family=Barlow);
    * { font-family: "Barlow"; box-sizing: border-box; }
    body { 
      text-align: center; 
      margin: 0;
      padding: 20px;
      background: #f0f0f0;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .page-container {
      display: flex;
      flex-wrap: wrap;
      gap: 2rem;
      justify-content: center;
      align-items: stretch;
      max-width: 1200px;
      margin: 0 auto;
    }
    .container {
      background: white;
      padding: 2rem;
      border-radius: 15px;
      box-shadow: 0 4px 6px rgba(0,0,0,0.1);
      width: 500px;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    .current-monitor {
      background: white;
      padding: 2rem;
      border-radius: 15px;
      box-shadow: 0 4px 6px rgba(0,0,0,0.1);
      width: 500px;
    }
    .current-display {
      display: flex;
      flex-direction: column;
      gap: 1rem;
      margin-top: 1rem;
    }
    .current-item {
      padding: 1rem;
      border-radius: 10px;
      color: white;
      text-align: left;
      display: flex;
      justify-content: space-between;
    }
    .current-red { background: linear-gradient(to right, #ff0000, #ff4444); }
    .current-green { background: linear-gradient(to right, #00ff00, #44ff44); }
    .current-blue { background: linear-gradient(to right, #0000ff, #4444ff); }
    .current-total { 
      background: linear-gradient(to right, #666, #999);
      font-weight: bold;
    }
    .vc-chrome {
      width: 100% !important;
      margin: 1rem 0;
    }
    .controls {
      width: 100%;
      margin-top: 1rem;
    }
    .brightness-control {
      margin: 1rem 0;
    }
    .brightness-control input {
      width: 100%;
    }
    .color-preview {
      width: 100%;
      height: 60px;
      border-radius: 10px;
      margin: 1rem 0;
      transition: all 0.3s ease;
    }
    
    @media (max-width: 768px) {
      .container,
      .current-monitor {
        width: 100%;
        max-width: 500px;
      }
      .page-container {
        flex-direction: column;
        align-items: center;
      }
    }
  </style>
</head>
<body>
  <div id="app"></div>
  <script>
    new Vue({
      el: "#app",
      components: {
        'chrome-picker': VueColor.Chrome
      },
      data: {
        color: {
          hex: "#000000",
          rgba: { r: 0, g: 0, b: 0, a: 1 }
        },
        brightness: 0,
        rainbow: false,
        currents: {
          red: 0,
          green: 0,
          blue: 0,
          total: 0
        }
      },
      methods: {
        updateColor(color) {
          this.color = color;
          const { r, g, b } = color.rgba;
          fetch(`/set_rgb?r=${r}&g=${g}&b=${b}`);
        },
        updateBrightness() {
          fetch(`/set_brightness?value=${this.brightness}`);
        },
        toggleRainbow() {
          fetch(`/rainbow?state=${this.rainbow}`);
        },
        async updateCurrents() {
          try {
            const response = await fetch('/get_currents');
            this.currents = await response.json();
          } catch (error) {
            console.error('Error fetching currents:', error);
          }
        }
      },
      mounted() {
        // Send initial state to the server
        const { r, g, b } = this.color.rgba;
        fetch(`/set_rgb?r=${r}&g=${g}&b=${b}`);
        fetch(`/set_brightness?value=${this.brightness}`);
        setInterval(this.updateCurrents, 200);
      },
      computed: {
        previewStyle() {
          const { r, g, b } = this.color.rgba;
          const brightness = this.brightness / 100;
          return {
            backgroundColor: `rgba(${r}, ${g}, ${b}, ${brightness})`,
            boxShadow: `0 0 15px rgba(${r}, ${g}, ${b}, ${brightness})`
          };
        }
      },
      template: `
        <div class="page-container">
          <div class="container">
            <h1 class="title">RGB Control</h1>
            
            <div class="color-preview" :style="previewStyle"></div>
            
            <chrome-picker 
              :value="color"
              @input="updateColor"
              :disable-alpha="true"
            ></chrome-picker>
            
            <div class="controls">
              <div class="brightness-control">
                <p>Brightness: {{ brightness }}%</p>
                <input 
                  type="range" 
                  min="0" 
                  max="100" 
                  v-model="brightness" 
                  @change="updateBrightness"
                />
              </div>
              
              <div class="rainbow-toggle">
                <label>
                  <input 
                    type="checkbox" 
                    v-model="rainbow" 
                    @change="toggleRainbow"
                  />
                  Rainbow Animation
                </label>
              </div>
            </div>
          </div>

          <div class="current-monitor">
            <h2>Current Monitor</h2>
            <div class="current-display">
              <div class="current-item current-red">
                <span>Red LED:</span>
                <span>{{ currents.red.toFixed(2) }} mA</span>
              </div>
              <div class="current-item current-green">
                <span>Green LED:</span>
                <span>{{ currents.green.toFixed(2) }} mA</span>
              </div>
              <div class="current-item current-blue">
                <span>Blue LED:</span>
                <span>{{ currents.blue.toFixed(2) }} mA</span>
              </div>
              <div class="current-item current-total">
                <span>Total Current:</span>
                <span>{{ currents.total.toFixed(2) }} mA</span>
              </div>
            </div>
          </div>
        </div>
      `
    });
  </script>
</body>
</html>
  )rawliteral";

  server.send(200, "text/html", html);
}