#include <WiFi.h>
#include <ESPAsyncWebServer.h>

#define ADC_PIN 4 // GPIO pin for ADC
#define V_REF 3.3 // Reference voltage of ESP32-S2 ADC

// WiFi credentials (AP mode)
const char* ssid = "Indus-Oscilloscope";
const char* password = "12345678";

// Web server instance
AsyncWebServer server(80);

// Variables to store the captured waveforms
String capturedWaveforms[4];
int captureCount = 0;

// HTML + JavaScript for the oscilloscope webpage with Time and Voltage Division labels
const char* htmlPage = R"rawliteral(
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IndusScope</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 0;
            padding: 0;
            background-color: #181818; /* Dark background */
            color: #e1e1e1; /* Light text */
        }
        h1 {
            font-size: 2em;
            margin: 20px;
        }
        .title {
            font-size: 2.5em;
            font-weight: bold;
            color: white; /* Bright white for title */
        }
        #oscilloscope {
            display: block;
            margin: 20px auto;
            border: 2px solid #ccc;
            box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.6);
            background-color: #000000; /* Black background for canvas */
        }
        .controls {
            margin: 20px;
        }
        .slider-container {
            margin-bottom: 10px;
        }
        .info {
            font-size: 1em;
            margin-top: 10px;
            color: #999999; /* Light text for info */
        }
        footer {
            margin-top: 20px;
            font-size: 0.9em;
            color: #e1e1e1; /* Light footer text */
        }
        .slider-container input[type="range"] {
            width: 80%;
            background-color: #333333; /* Darker slider background */
        }
        .capture-grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 20px;
            margin-top: 20px;
        }
        .capture-item {
            background-color: #222222;
            padding: 10px;
            border: 2px solid #ccc;
            border-radius: 8px;
        }
    </style>
    <script>
        let canvas, ctx;
        let timeDivision = 1; // Time scaling factor
        let voltageDivision = 1; // Voltage scaling factor
        let capturedWaveforms = []; // Array to store captured waveforms

        const drawGrid = () => {
            ctx.strokeStyle = "#FFFF00"; // Grid lines
            ctx.lineWidth = 1;

            const divisionsX = 10; // Vertical divisions
            const divisionsY = 5;  // Horizontal divisions

            const timePerDiv = (timeDivision * 10).toFixed(2) + " ms/div";
            const voltagePerDiv = (voltageDivision * 1).toFixed(2) + " V/div";

            // Draw vertical lines and time labels
            for (let x = 0; x <= canvas.width; x += canvas.width / divisionsX) {
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, canvas.height);
                ctx.stroke();
                if (x > 0) {
                    ctx.fillStyle = "#e1e1e1";
                    ctx.font = "10px Arial";
                    ctx.fillText(timePerDiv, x - 15, canvas.height - 5); // Time labels
                }
            }

            // Draw horizontal lines and voltage labels
            for (let y = 0; y <= canvas.height; y += canvas.height / divisionsY) {
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(canvas.width, y);
                ctx.stroke();
                if (y > 0) {
                    ctx.fillStyle = "#e1e1e1";
                    ctx.font = "10px Arial";
                    ctx.fillText(voltagePerDiv, 5, y - 5); // Voltage labels
                }
            }
        };

        const fetchData = async () => {
            const response = await fetch('/data');
            const json = await response.json();
            return json;
        };

        const updateGraph = async () => {
            const data = await fetchData();

            // Clear the canvas
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Draw grid
            drawGrid();

            // Draw waveform
            ctx.strokeStyle = "#76ff03"; // Green waveform
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(0, canvas.height - data.waveform[0] * voltageDivision);

            data.waveform.forEach((value, index) => {
                const x = index * (canvas.width / (data.waveform.length * timeDivision));
                const y = canvas.height - value * voltageDivision;
                ctx.lineTo(x, y);
            });

            ctx.stroke();

            // Display measurements
            ctx.fillStyle = "#e1e1e1"; // White text for measurements
            ctx.font = "14px Arial";
            ctx.fillText(`Frequency: ${data.frequency.toFixed(2)} Hz`, 10, 20);
            ctx.fillText(`Peak Voltage: ${data.peakVoltage.toFixed(2)} V`, 10, 40);
            ctx.fillText(`Average Voltage: ${data.avgVoltage.toFixed(2)} V`, 10, 60);

            requestAnimationFrame(updateGraph);
        };

        const updateTimeDivision = (value) => {
            timeDivision = parseFloat(value);
        };

        const updateVoltageDivision = (value) => {
            voltageDivision = parseFloat(value);
        };

        const captureWaveform = () => {
            if (capturedWaveforms.length < 4) {
                capturedWaveforms.push(canvas.toDataURL());
                updateCaptureGrid();
            }
        };

        const updateCaptureGrid = () => {
            const captureGrid = document.getElementById('captureGrid');
            captureGrid.innerHTML = ''; // Clear existing captures

            capturedWaveforms.forEach((waveformData, index) => {
                const captureItem = document.createElement('div');
                captureItem.className = 'capture-item';
                captureItem.innerHTML = `<img src="${waveformData}" width="100%" />`;
                captureGrid.appendChild(captureItem);
            });
        };

        window.onload = () => {
            canvas = document.getElementById('oscilloscope');
            ctx = canvas.getContext('2d');
            updateGraph();
        };
    </script>
</head>
<body>
    <h1 class="title">Indus Oscilloscope</h1>
    <canvas id="oscilloscope" width="800" height="400"></canvas>

    <div class="controls">
        <div class="slider-container">
            <label for="timeDivision">Time Division:</label>
            <input type="range" id="timeDivision" min="0.1" max="2" step="0.1" value="1" oninput="updateTimeDivision(this.value)">
        </div>
        <div class="slider-container">
            <label for="voltageDivision">Voltage Division:</label>
            <input type="range" id="voltageDivision" min="0.5" max="2" step="0.1" value="1" oninput="updateVoltageDivision(this.value)">
        </div>
        <button onclick="captureWaveform()">Capture Waveform</button>
    </div>

    <div class="info">Adjust the sliders to change Time and Voltage Division.</div>

    <div class="capture-grid" id="captureGrid">
        <!-- Captured waveforms will be displayed here in a grid -->
    </div>

    <footer>Powered by IndusBoard Technologies</footer>
</body>
</html>
)rawliteral";

// Function to calculate signal properties
void handleDataRequest(AsyncWebServerRequest* request) {
    const int samples = 100;
    int rawADC[samples];
    int maxADC = 0;
    int minADC = 4095;
    float waveform[samples];
    float peakVoltage = 0.0;
    float totalVoltage = 0.0;
    int zeroCrossings = 0;
    bool lastWasPositive = false;

    for (int i = 0; i < samples; i++) {
        rawADC[i] = analogRead(ADC_PIN);

        if (rawADC[i] > maxADC) maxADC = rawADC[i];
        if (rawADC[i] < minADC) minADC = rawADC[i];

        waveform[i] = (rawADC[i] / 4095.0) * V_REF;

        if (waveform[i] > peakVoltage) {
            peakVoltage = waveform[i];
        }

        totalVoltage += waveform[i];

        bool isPositive = waveform[i] > (V_REF / 2);
        if (i > 0 && isPositive != lastWasPositive) {
            zeroCrossings++;
        }
        lastWasPositive = isPositive;

        delayMicroseconds(100);
    }

    float avgVoltage = totalVoltage / samples;
    float frequency = (zeroCrossings / 2.0) / (samples * 0.0001);

    String json = "{";
    json += "\"waveform\":[";
    for (int i = 0; i < samples; i++) {
        int scaledValue = map(rawADC[i], minADC, maxADC, 10, 390);
        json += String(400 - scaledValue);
        if (i < samples - 1) json += ",";
    }
    json += "],";
    json += "\"peakVoltage\":" + String(peakVoltage) + ",";
    json += "\"avgVoltage\":" + String(avgVoltage) + ",";
    json += "\"frequency\":" + String(frequency);
    json += "}";

    request->send(200, "application/json", json);
}

void setup() {
    Serial.begin(115200);
    pinMode(33,1);
    digitalWrite(33,1);
    pinMode(ADC_PIN, INPUT);

    WiFi.softAP(ssid, password);
    Serial.println("Access Point started. Connect to: Indus-Oscilloscope");

    server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
        request->send(200, "text/html", htmlPage);
    });
    server.on("/data", HTTP_GET, handleDataRequest);

    server.begin();
    Serial.println("Server started. Go to http://192.168.4.1 in your browser.");
}

void loop() {
    // Nothing needed here, handled by AsyncWebServer
}
