#include <Wire.h>
#include <SPI.h>
#include <Arduino.h>
#include "Display.h"
#include "Power.h"
#include "Storage.h"
#include "PwmPin.h"

#define EB_FAST 30     // таймаут быстрого поворота, мс
#define EB_DEB 80      // дебаунс кнопки, мс
#define EB_HOLD 600   // таймаут удержания кнопки, мс
#define EB_STEP 500    // период срабатывания степ, мс
#define EB_CLICK 400   // таймаут накликивания, мс

#include "EncButton.h"

#define DEFAULT_VOLTAGE_READ_DELAY 10000

#define DEFAULT_MODE 0
#define VAPE_MODE 1
#define MENU_MODE 2

Display display{};

Power power;

Storage storage;

unsigned long lastVoltageRead = 0;
unsigned long lastFPSUpdate = 0;
unsigned long lastFPSDisplay = 0;
uint16_t readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;

struct {
    EncButton<EB_TICK, 2> vape;
} buttons;

KeyFrame keyFrames[]{
        {"Vaping",    200},
        {"Vaping.",   200},
        {"Vaping..",  200},
        {"Vaping...", 200}
};

KeyFrame lowBatteryFrames[]{
        {"Battery Low...", 333},
        {" ",              1333}
};

struct {
    Animation vaping{keyFrames, 4, true};
    Animation lowBattery{lowBatteryFrames, 2, true};
} animations;

struct {
    Pin led{LED_BUILTIN};
    PwmPin coil{9};
    Pin charger{6};
} pins;

void setup() {
    Serial.begin(11520);
    display.init();
    display.clear();
    // storage.writeData();
    // storage.readData();
}

uint8_t currentMode = DEFAULT_MODE;
unsigned long vapeStartTime;
uint16_t maxVapeTime = 4000;
bool isModeChanged = true;
bool batteryLowMode = false;

void loop() {
    buttons.vape.tick();
    // if (millis() - lastFPSUpdate > 1000 || lastFPSUpdate == 0) {
    // display.frames = 0;
    // lastFPSUpdate = millis();
    // }
    if (millis() - lastVoltageRead > readVoltageDelay || lastVoltageRead == 0) {
        Serial.println(power.readBatteryVoltage());
        lastVoltageRead = millis();
        display.printHeader(power.percentage, true);
        // display.printFooter("V:" + power.readableVoltage);
    }
    if (batteryLowMode == power.isCharged) {
        batteryLowMode = !power.isCharged;
        isModeChanged = true;
    }
    if (batteryLowMode) {
        batteryLow();
    } else {
        if (currentMode == VAPE_MODE) {
            vapeAction();
        } else if (currentMode == MENU_MODE) {
            menuAction();
        } else {
            defaultAction();
        }
    }
    display.update();

    // if (millis() - lastFPSDisplay > 250 || lastFPSDisplay == 0) {
    //    display.printFps();
    // lastFPSDisplay = millis();
    // }
}

void batteryLow() {
    if (isModeChanged) {
        Serial.println("Battery Low");
        isModeChanged = false;
        pins.coil.write(false);
        readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;
        currentMode = DEFAULT_MODE;
    }
    display.playAnimation(animations.lowBattery);
}

void defaultAction() {
    if (isModeChanged) {
        Serial.println("Default mode enabled");
        isModeChanged = false;
        pins.led.write(false);
        display.println("BOXMOD");
        readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;
    }
    if (buttons.vape.isHolded()) {
        setMode(VAPE_MODE);
    } else if (buttons.vape.hasClicks(2)) {
        setMode(MENU_MODE);
    }
}

void vapeAction() {
    if (isModeChanged) {
        Serial.println("Vape mode enabled");
        vapeStartTime = millis();
    }
    pins.led.write(true);
    if (pins.charger.read()) {
        pins.coil.write(true);
    }
    display.playAnimation(animations.vaping);
    readVoltageDelay = 5000;
    isModeChanged = false;
    if (millis() - vapeStartTime >= maxVapeTime || buttons.vape.isRelease()) {
        pins.coil.write(false);
        setMode(DEFAULT_MODE);
    }
}

void menuAction() {
    if (isModeChanged) {
        Serial.println("Menu mode enabled");
        readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;
        isModeChanged = false;
        pins.led.write(false);
    }
    display.println("SETTINGS // TODO");

    if (buttons.vape.hasClicks(3)) {
        setMode(DEFAULT_MODE);
    }
}

void setMode(uint8_t newMode) {
    if (currentMode != newMode) {
        currentMode = newMode;
        isModeChanged = true;
    }
}