#include <OneButton.h>
#include "config.h"

OneButton buttons[NUM_OF_BUTTONS] = 
{
    OneButton(P_1),
    OneButton(P_2),
    OneButton(P_3),
    OneButton(P_4),
    OneButton(P_5)
};

ProgramType currentProgram = ProgramType::NONE;
bool isNewSequence = false;

void setRelayState(uint8_t pin, bool state)
{
    digitalWrite(pin, state ^ INVERT_RELAY_LOGIC);
}

void setAllOff()
{
    for (uint8_t i = 0; i < NUM_OF_OUTPUTS; i++)
    {
        setRelayState(outputs[i], LOW);
    }
}

bool generateSequence(uint8_t outA, uint8_t outB)
{
    static uint8_t lastActiveOut = 0;
    static bool lastOutState = 0;
    static unsigned long lastStateChangeTime = 0;
    static int switchCount = 0;

    if (isNewSequence)
    {
        isNewSequence = false;
        lastStateChangeTime = millis();
        switchCount = 0;
        lastActiveOut = outA;
        lastOutState = HIGH;
        setRelayState(lastActiveOut, lastOutState);
    }

    if (switchCount >= 10)
    {
        return false;
    }

    unsigned long currentTime = millis();
    unsigned long elapsedTime = currentTime - lastStateChangeTime;

    if (lastOutState == LOW && elapsedTime >= 900)
    {
        switchCount++;

        if (switchCount >= 10)
        {
            setRelayState(outA, LOW);
            setRelayState(outB, LOW);
            return false;
        }

        lastOutState = HIGH;
        lastStateChangeTime = currentTime;
        setRelayState(lastActiveOut, lastOutState);
    }
    else if (lastOutState == HIGH && elapsedTime >= 100)
    {
        lastOutState = LOW;
        lastStateChangeTime = currentTime;
        setRelayState(lastActiveOut, lastOutState);
        lastActiveOut = (lastActiveOut == outA) ? outB : outA;
    }

    return true;
}

void program_p1(bool isStart = false)
{
    double voltage = (double)analogRead(INPUT_0) * (5.0 / 1023.0);

    if (voltage < 2.5)
    {
        setRelayState(OUT_1, HIGH);
    }
    else if (voltage > 3.0)
    {
        setRelayState(OUT_1, LOW);
    }
}

void program_p2(bool isStart = false)
{
    static unsigned long startTime = 0;

    if (isStart)
    {
        startTime = millis();
        isNewSequence = true;
    }

    program_p1();

    if (millis() - startTime < 2000)
    {
        return;
    }

    generateSequence(OUT_2, OUT_3);
}

void program_p3(bool isStart = false)
{
    static unsigned long startTime = 0;

    if (isStart)
    {
        startTime = millis();
        isNewSequence = true;
    }

    program_p1();

    if (millis() - startTime < 2000)
    {
        return;
    }

    generateSequence(OUT_4, OUT_5);
}

void program_p4(bool isStart = false)
{
    static unsigned long startTime = 0;

    if (isStart)
    {
        startTime = millis();
        isNewSequence = true;
        setRelayState(OUT_6, HIGH);
    }

    program_p1();

    if (millis() - startTime < 2000)
    {
        return;
    }

    if (!generateSequence(OUT_4, OUT_5))
    {
        setRelayState(OUT_6, LOW);
    }
}

void program_p5(bool isStart = false)
{
    static unsigned long startTime = 0;

    if (isStart)
    {
        startTime = millis();
        setRelayState(OUT_7, HIGH);
    }

    if (millis() - startTime > 1000)
    {
        setRelayState(OUT_7, LOW);
    }
}

void handleButtonPress(void *button)
{
    int pin = ((OneButton*)button)->pin();
    setAllOff();

    if (pin == P_1)
    {
        program_p1(true);
        currentProgram = ProgramType::PROG_1;
    }
    else if (pin == P_2)
    {
        program_p2(true);
        currentProgram = ProgramType::PROG_2;
    }
    else if (pin == P_3)
    {
        program_p3(true);
        currentProgram = ProgramType::PROG_3;
    }
    else if (pin == P_4)
    {
        program_p4(true);
        currentProgram = ProgramType::PROG_4;
    }
    else if (pin == P_5)
    {
        program_p5(true);
        currentProgram = ProgramType::PROG_5;
    }
}

void setup()
{
    for (uint8_t i = 0; i < NUM_OF_BUTTONS; i++)
    {
        buttons[i].attachLongPressStart(handleButtonPress, &buttons[i]);
        buttons[i].setLongPressIntervalMs(1000);
    }

    for (uint8_t i = 0; i < NUM_OF_OUTPUTS; i++)
    {
        pinMode(outputs[i], OUTPUT);
        setRelayState(outputs[i], LOW);
    }
}

void loop()
{
    for (uint8_t i = 0; i < NUM_OF_BUTTONS; i++)
    {
        buttons[i].tick();
    }

    if (currentProgram == ProgramType::PROG_1)
    {
        program_p1();
    }
    else if (currentProgram == ProgramType::PROG_2)
    {
        program_p2();
    }
    else if (currentProgram == ProgramType::PROG_3)
    {
        program_p3();
    }
    else if (currentProgram == ProgramType::PROG_4)
    {
        program_p4();
    }
    else if (currentProgram == ProgramType::PROG_5)
    {
        program_p5();
    }
}
D0D1D2D3D4D5D6D7GNDLOGIC