class PIDController {
private:
    double Kp;
    double Ki;
    double Kd;

    double setPoint;
    double integral;
    double prevError;
    unsigned long prevTime;

    // Auto-tuning variables
    bool autoTune;
    double outputStart;
    double outputStep;
    unsigned long tuneStartTime;
    unsigned long tuneDuration;
    double peakHigh;
    double peakLow;
    int peakCount;

public:
    PIDController(double kp, double ki, double kd)
        : Kp(kp), Ki(ki), Kd(kd), setPoint(0), integral(0), prevError(0), prevTime(0),
          autoTune(false), outputStart(0), outputStep(0), tuneDuration(0), peakHigh(0), peakLow(0), peakCount(0) {}

    void setSetPoint(double sp) {
        setPoint = sp;
    }

    void startAutoTune(double startOutput, double step, unsigned long duration) {
        autoTune = true;
        outputStart = startOutput;
        outputStep = step;
        tuneStartTime = millis();
        tuneDuration = duration;
        peakCount = 0;
        peakHigh = 0;
        peakLow = 0;
    }

    double compute(double input) {
        unsigned long currentTime = millis();

        if (autoTune && currentTime - tuneStartTime < tuneDuration) {
            return autoTuneStep(input);
        } else {
            autoTune = false;
            return normalPID(input);
        }
    }

private:
    double normalPID(double input) {
        double deltaTime = (millis() - prevTime) / 1000.0;
        double error = setPoint - input;
        integral += error * deltaTime;
        double derivative = (error - prevError) / deltaTime;

        double output = Kp * error + Ki * integral + Kd * derivative;

        prevError = error;
        prevTime = millis();

        return output;
    }

    double autoTuneStep(double input) {
        unsigned long currentTime = millis();
        double timeSinceStart = (currentTime - tuneStartTime) / 1000.0;

        double output = outputStart + outputStep * timeSinceStart;

        // Record peak values and count peaks
        if (input > peakHigh) peakHigh = input;
        if (input < peakLow) peakLow = input;

        // Check for peak
        if (/* condition to detect peak */) {
            peakCount++;
            // Update tuning parameters based on detected peaks
        }

        return output;
    }

    // Add additional methods for tuning calculations
};
/*
#include <Arduino.h>
#include <cmath>

class PIDController {
private:
    double Kp;
    double Ki;
    double Kd;

    double setPoint;
    double integral;
    double prevError;
    unsigned long prevTime;

    double lastInput; // For estimating time to reach set point
    bool isStable;

public:
    PIDController(double kp, double ki, double kd)
        : Kp(kp), Ki(ki), Kd(kd), setPoint(0), integral(0), prevError(0), prevTime(millis()), lastInput(0), isStable(false) {}

    void setSetPoint(double sp) {
        setPoint = sp;
        isStable = false;
    }

    double compute(double input) {
        unsigned long currentTime = millis();
        double deltaTime = (currentTime - prevTime) / 1000.0; // Time in seconds
        double error = setPoint - input;
        integral += error * deltaTime;
        double derivative = (error - prevError) / deltaTime;

        double output = Kp * error + Ki * integral + Kd * derivative;

        prevError = error;
        prevTime = currentTime;
        lastInput = input;

        return output;
    }

    double estimateTimeToSetPoint() {
        double error = setPoint - lastInput;
        if (std::abs(error) < 0.01 * std::abs(setPoint)) { // Threshold for stability
            isStable = true;
            return 0.0;
        }

        if (isStable) return 0.0;

        double rateOfChange = lastInput - prevError;
        if (rateOfChange == 0) return -1.0; // Indefinite or unknown time

        double estimatedTime = error / rateOfChange;
        return estimatedTime > 0 ? estimatedTime : -1.0; // Return -1 if estimated time is negative
    }
};
*/
/*
#include <max6675.h>

class Max6675Sensor : public TemperatureSensor {
private:
    int thermoDO;
    int thermoCS;
    int thermoCLK;
    MAX6675 thermocouple;

public:
    Max6675Sensor(int doPin, int csPin, int clkPin) 
        : thermoDO(doPin), thermoCS(csPin), thermoCLK(clkPin), thermocouple(clkPin, csPin, doPin) {}

    double readTemperature() override {
        return thermocouple.readCelsius();
    }
};


class TemperatureSensor {
public:
    // Virtual destructor to ensure proper cleanup of derived classes
    virtual ~TemperatureSensor() {}

    // Pure virtual function to be implemented by derived classes
    virtual double readTemperature() = 0;
};
*/