#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <INA226.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_; 

// WiFi Configuration
const char *ap_ssid = "RGB_Controller";      // Name of the WiFi network to create
const char *ap_password = "12345678";        // Password for the WiFi network
IPAddress local_ip(192,168,4,1);            // Static IP address for the access point
IPAddress gateway(192,168,4,1);             // Gateway (same as static IP)
IPAddress subnet(255,255,255,0);            // Subnet mask

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


ESP8266WebServer server(80);

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;

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;  // Stop rainbow when setting manual color
    setRGB(redValue, greenValue, blueValue, brightness);
    server.send(200, "text/plain", "RGB updated");
  } else {
    server.send(400, "text/plain", "Missing RGB arguments");
  }
  delay(10);
}

void handleSetBrightness() {
  if (server.hasArg("value")) {
    brightness = server.arg("value").toFloat();
    setRGB(redValue, greenValue, blueValue, brightness);
    server.send(200, "text/plain", "Brightness updated");
  } else {
    server.send(400, "text/plain", "Missing brightness argument");
  }
}

void handleRainbow() {
  if (server.hasArg("state")) {
    rainbowActive = server.arg("state") == "true";
    if (!rainbowActive) {
      // Restore the last manual color when rainbow is turned off
      setRGB(redValue, greenValue, blueValue, brightness);
    }
  }
  server.send(200, "text/plain", rainbowActive ? "Rainbow started" : "Rainbow stopped");
}


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);

  // Initialize I2C and INA226 sensors
  delay(100);
  Wire_.begin(5, 4);
  delay(200);
  scanI2CBus(Wire_);
  delay(200);
  initializeINA226(redINA, "RED");
  delay(200);
  initializeINA226(greenINA, "GREEN");
  delay(200);
  initializeINA226(blueINA, "BLUE");

  // Configure ESP8266 as Access Point
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  WiFi.softAP(ap_ssid, ap_password);

  Serial.println("WiFi Access Point Created");
  Serial.print("SSID: ");
  Serial.println(ap_ssid);
  Serial.print("Password: ");
  Serial.println(ap_password);
  Serial.print("IP Address: ");
  Serial.println(local_ip);

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

  server.begin();
  Serial.println("HTTP server started");
}

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>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        * { 
            box-sizing: border-box; 
            font-family: Arial, sans-serif;
        }
        body { 
            margin: 0;
            padding: 20px;
            background: #f0f0f0;
            min-height: 100vh;
        }
        .page-container {
            max-width: 800px;
            margin: 0 auto;
            display: grid;
            gap: 20px;
        }
        .card {
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .color-preview {
            width: 100%;
            height: 60px;
            border-radius: 8px;
            margin: 10px 0;
            border: 1px solid #ccc;
        }
        .color-inputs {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            margin-bottom: 20px;
        }
        .color-input {
            display: flex;
            flex-direction: column;
        }
        .color-input label {
            margin-bottom: 5px;
            color: #666;
        }
        input[type="range"] {
            width: 100%;
            margin: 10px 0;
        }
        input[type="number"] {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .current-item {
            padding: 10px;
            margin: 5px 0;
            border-radius: 5px;
            color: white;
            display: flex;
            justify-content: space-between;
        }
        .red { background: linear-gradient(to right, #ff0000, #ff4444); }
        .green { background: linear-gradient(to right, #00ff00, #44ff44); }
        .blue { background: linear-gradient(to right, #0000ff, #4444ff); }
        .total { background: linear-gradient(to right, #666, #999); }
        .checkbox-wrapper {
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <div class="page-container">
        <div class="card">
            <h2>RGB Control</h2>
            <div class="color-preview" id="colorPreview"></div>
            
            <div class="color-inputs">
                <div class="color-input">
                    <label>Red</label>
                    <input type="range" id="redSlider" min="0" max="255" value="0">
                    <input type="number" id="redValue" min="0" max="255" value="0">
                </div>
                <div class="color-input">
                    <label>Green</label>
                    <input type="range" id="greenSlider" min="0" max="255" value="0">
                    <input type="number" id="greenValue" min="0" max="255" value="0">
                </div>
                <div class="color-input">
                    <label>Blue</label>
                    <input type="range" id="blueSlider" min="0" max="255" value="0">
                    <input type="number" id="blueValue" min="0" max="255" value="0">
                </div>
            </div>

            <div class="brightness-control">
                <label>Brightness</label>
                <input type="range" id="brightnessSlider" min="0" max="100" value="100">
                <span id="brightnessValue">100%</span>
            </div>

            <div class="checkbox-wrapper">
                <label>
                    <input type="checkbox" id="rainbowToggle">
                    Rainbow Mode
                </label>
            </div>
        </div>

        <div class="card">
            <h2>Current Monitor</h2>
            <div id="currentDisplay">
                <div class="current-item red">
                    <span>Red LED:</span>
                    <span id="redCurrent">0.00 mA</span>
                </div>
                <div class="current-item green">
                    <span>Green LED:</span>
                    <span id="greenCurrent">0.00 mA</span>
                </div>
                <div class="current-item blue">
                    <span>Blue LED:</span>
                    <span id="blueCurrent">0.00 mA</span>
                </div>
                <div class="current-item total">
                    <span>Total Current:</span>
                    <span id="totalCurrent">0.00 mA</span>
                </div>
            </div>
        </div>
    </div>

    <script>
        // Color control elements
        const redSlider = document.getElementById('redSlider');
        const greenSlider = document.getElementById('greenSlider');
        const blueSlider = document.getElementById('blueSlider');
        const redValue = document.getElementById('redValue');
        const greenValue = document.getElementById('greenValue');
        const blueValue = document.getElementById('blueValue');
        const brightnessSlider = document.getElementById('brightnessSlider');
        const brightnessValue = document.getElementById('brightnessValue');
        const colorPreview = document.getElementById('colorPreview');
        const rainbowToggle = document.getElementById('rainbowToggle');

        // Current monitoring elements
        const redCurrent = document.getElementById('redCurrent');
        const greenCurrent = document.getElementById('greenCurrent');
        const blueCurrent = document.getElementById('blueCurrent');
        const totalCurrent = document.getElementById('totalCurrent');

        // Sync sliders with number inputs
        function syncInputs(slider, value) {
            slider.oninput = () => {
                value.value = slider.value;
                updateColor();
            };
            value.oninput = () => {
                slider.value = value.value;
                updateColor();
            };
        }

        syncInputs(redSlider, redValue);
        syncInputs(greenSlider, greenValue);
        syncInputs(blueSlider, blueValue);

        // Update color preview and send to ESP
        function updateColor() {
            const r = redSlider.value;
            const g = greenSlider.value;
            const b = blueSlider.value;
            const brightness = brightnessSlider.value / 100;
            
            colorPreview.style.backgroundColor = 
                `rgba(${r}, ${g}, ${b}, ${brightness})`;
            
            fetch(`/set_rgb?r=${r}&g=${g}&b=${b}`);
        }

        // Brightness control
        brightnessSlider.oninput = () => {
            const value = brightnessSlider.value;
            brightnessValue.textContent = value + '%';
            fetch(`/set_brightness?value=${value}`);
            updateColor();
        };

        // Rainbow mode
        rainbowToggle.onchange = () => {
            fetch(`/rainbow?state=${rainbowToggle.checked}`);
        };

        // Update current readings
        function updateCurrents() {
            fetch('/get_currents')
                .then(response => response.json())
                .then(data => {
                    redCurrent.textContent = data.red.toFixed(2) + ' mA';
                    greenCurrent.textContent = data.green.toFixed(2) + ' mA';
                    blueCurrent.textContent = data.blue.toFixed(2) + ' mA';
                    totalCurrent.textContent = data.total.toFixed(2) + ' mA';
                });
        }

        // Update currents every 200ms
        setInterval(updateCurrents, 200);
    </script>
</body>
</html>
)rawliteral";

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