#include <WiFi.h>
#include <WebServer.h>

// Motor and encoder pins
const int in1Pin = 33;
const int in2Pin = 27;
const int enAPin = 32;
const int encoderPinA = 34;
const int encoderPinB = 35;

volatile int pulseCount = 0;
int lastEncoded = 0;
int speedVal = 0;
String direction = "stop";

WebServer server(80);

// WiFi credentials
const char* ssid = "ESP32_Motor";
const char* password = "12345678";

// Encoder ISR
void updateEncoder() {
  int MSB = digitalRead(encoderPinA);
  int LSB = digitalRead(encoderPinB);
  int encoded = (MSB << 1) | LSB;
  int sum = (lastEncoded << 2) | encoded;
  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) pulseCount++;
  else if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) pulseCount--;
  lastEncoded = encoded;
}

// HTML interface (RoundSlider)
void handleRoot() {
  server.send(200, "text/html", R"rawliteral(

<!DOCTYPE html>
<html>
<head>
  <title>Motor Control</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:wght@600&display=swap" rel="stylesheet">
  <style>
    body {
      font-family: 'IBM Plex Serif', serif;
      background-color: #fffef7;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
    }

    .container {
      width: 420px;
      border: 4px solid #9c9494;
      padding: 20px;
      box-shadow: 0 0 12px rgba(0,0,0,0.2);
      background: white;
    }

    .position {
      color: #387478;
      font-size: 22px;
      font-weight: bold;
      margin-bottom: 10px;
    }

    .position span {
      display: inline-block;
      border: 1px solid #000;
      padding: 4px 10px;
      min-width: 60px;
      text-align: center;
    }

    .speed-label {
      font-size: 20px;
      color: #09336e;
      margin-top: 15px;
    }

    #speedSlider {
  -webkit-appearance: none;
  width: 100%;
  height: 12px;
  background: #e9e9e9;
  border-radius: 8px;
  outline: none;
  position: relative;
  overflow: visible; /* ✅ allow thumb to overflow */
}

#speedSlider::-webkit-slider-runnable-track {
  height: 12px;
  background: linear-gradient(to right, #0f2f35 var(--val, 0%), #e9e9e9 var(--val, 0%));
  border-radius: 8px;
}

#speedSlider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  margin-top: -6px; /* this centers the thumb */
  width: 24px;
  height: 24px;
  background: white;
  border-radius: 50%;
  border: 2px solid #ccc;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
  cursor: pointer;
  position: relative;
  z-index: 2;
}

#speedSlider::-moz-range-track {
  background: #e9e9e9;
  height: 12px;
  border-radius: 8px;
}

#speedSlider::-moz-range-progress {
  background-color: #0f2f35;
  height: 12px;
  border-radius: 8px;
}

#speedSlider::-moz-range-thumb {
  width: 24px;
  height: 24px;
  background: white;
  border-radius: 50%;
  border: 2px solid #ccc;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
  cursor: pointer;
}

    .direction {
        font-size: 20px;
        color: #2c3037;
        font-weight: bold;
        margin-top: 15px;
    }
    .label-title {
  font-size: 20px;
  color: #2c3037;
  font-weight: bold;
  margin-top: 15px;
}


    .arrow-buttons {
      display: flex;
      justify-content: space-around;
      margin-top: 10px;
    }

    .arrow-buttons button {
      font-size: 32px;
      font-weight: bold;
      padding: 0;
      width: 70px;
      height: 70px;
      border-radius: 20px; /* Rounded square. Change to 50% for perfect circle */
      background-color: white;
      color: #333333;
      border: 4px solid #333333;
      cursor: pointer;
      transition: all 0.3s ease;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .arrow-buttons button:hover {
      background-color: #eeeeee;
    }

    .arrow-buttons button.active {
      background-color: #333333;
      color: white;
      border-color: #333333;
    }

    canvas {
      margin-top: 20px;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="position">Position: <span id="pos">0</span></div>
    <div class="speed-label">Speed: <span id="speedVal">0</span></div>
    <input type="range" min="0" max="255" value="0" id="speedSlider" oninput="setSpeed(this.value)">
    <div class="direction"></div>
    <div class="arrow-buttons">
        <button id="leftBtn" onclick="setDir('left')">&#8592;</button>
        <button id="stopBtn" onclick="setDir('stop')">&#9632;</button>
        <button id="rightBtn" onclick="setDir('right')">&#8594;</button>
    </div>
    <canvas id="speedChart" width="400" height="200"></canvas>
  </div>

  <script>
    let currentSpeed = 0;
    let labels = [];
    let data = [];

    const speedSlider = document.getElementById("speedSlider");
    const speedDisplay = document.getElementById("speedVal");
    const ctx = document.getElementById('speedChart').getContext('2d');

    const chart = new Chart(ctx, {
      type: 'line',
      data: {
        labels: labels,
        datasets: [{
          label: 'Speed',
          data: data,
          borderColor: '#629584',
          tension: 0.2,
          fill: false
        }]
      },
      options: {
        scales: {
          x: { display: false },
          y: { min: 0, max: 255 }
        }
      }
    });

    function setSpeed(val) {
        currentSpeed = parseInt(val);
        speedDisplay.textContent = val;
        document.getElementById("speedSlider").style.setProperty('--val', (val / 255) * 100 + '%');
        fetch("/setSpeed?value=" + val);
    }


    function setDir(dir) {
      fetch("/setDir?value=" + dir);

      // Reset all button states
      document.getElementById("leftBtn").classList.remove("active");
      document.getElementById("rightBtn").classList.remove("active");
      document.getElementById("stopBtn").classList.remove("active");

      // Apply active style
      if (dir === "left") {
        document.getElementById("leftBtn").classList.add("active");
      } else if (dir === "right") {
        document.getElementById("rightBtn").classList.add("active");
      } else if (dir === "stop") {
        document.getElementById("stopBtn").classList.add("active");
      }
    }

    function updateGraph() {
      const now = new Date().toLocaleTimeString();
      if (labels.length >= 20) {
        labels.shift();
        data.shift();
      }
      labels.push(now);
      data.push(currentSpeed);
      chart.update();
    }

    setInterval(() => {
      fetch("/getPos")
        .then(res => res.text())
        .then(val => {
          document.getElementById("pos").textContent = val;
        });

      updateGraph();
    }, 1000);
  </script>
</body>
</html>

)rawliteral");
}

// REST endpoints
void handleSetSpeed() {
  if (server.hasArg("value")) {
    speedVal = server.arg("value").toInt();
    analogWrite(enAPin, speedVal);
  }
  server.send(200, "text/plain", "OK");
}

void handleSetDir() {
  if (server.hasArg("value")) {
    direction = server.arg("value");
    if (direction == "left") {
      digitalWrite(in1Pin, HIGH);
      digitalWrite(in2Pin, LOW);
    } else if (direction == "right") {
      digitalWrite(in1Pin, LOW);
      digitalWrite(in2Pin, HIGH);
    } else {
      digitalWrite(in1Pin, LOW);
      digitalWrite(in2Pin, LOW);
    }
  }
  server.send(200, "text/plain", "OK");
}

void handleGetPos() {
  server.send(200, "text/plain", String(pulseCount));
}

void setup() {
  Serial.begin(115200);
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(enAPin, OUTPUT);
  pinMode(encoderPinA, INPUT);
  pinMode(encoderPinB, INPUT);

  attachInterrupt(digitalPinToInterrupt(encoderPinA), updateEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPinB), updateEncoder, CHANGE);

  WiFi.softAP(ssid, password);
  Serial.println("Access Point Started: ESP32_Motor");

  server.on("/", handleRoot);
  server.on("/setSpeed", handleSetSpeed);
  server.on("/setDir", handleSetDir);
  server.on("/getPos", handleGetPos);
  server.begin();
}

void loop() {
  server.handleClient();
}