#include "config.h"

#define DEFAULT_VOLTAGE_READ_DELAY 10000

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

#define WIFI_POINTS_COUNT 3

Display display{};

Power power;

Storage storage;

unsigned long lastVoltageRead = DEFAULT_VOLTAGE_READ_DELAY;

uint16_t readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;

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

OTA ota{"InfinitumMod"};

uint8_t number = 0;

struct WifiPoint {
    String ssid;
    String password;
};

WifiPoint wifiPoints[WIFI_POINTS_COUNT] = {
        {"ares-phone-pixel", "password"},
        {"ASUS",             "samik2003"},
        {"WebDev",           "devMaster#999"}
};


struct {
    EncButton<EB_TICK, 0, 15, 12> 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 {
    PwmPin coil{14};
    Pin charger{26};
} pins;

bool flag = false;
unsigned long lastWifiStatusCheck = 10000;

void setMode(uint8_t newMode, bool force = false) {
    if (currentMode != newMode || force) {
        currentMode = newMode;
        isModeChanged = true;
    }
}

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;
        display.println(" ");
        readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;
    }
    display.println(String(buttons.vape.counter));
    pins.coil.write(false);
    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();
        isModeChanged = false;
    }
    pins.coil.write(true);
    display.playAnimation(animations.vaping);
    readVoltageDelay = 5000;
    bool isReleased = !buttons.vape.isHold();
    if (isReleased || millis() - vapeStartTime >= maxVapeTime) {
        pins.coil.write(false);
        setMode(DEFAULT_MODE);
    }
}

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

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

int8_t isRemembered(const String &ssid) {
    for (int8_t i = 0; i < WIFI_POINTS_COUNT; i++) {
        if (wifiPoints[i].ssid == ssid) {
            return i;
        }
    }
    return -1;
}


void onWiFiConnect(const WiFiEventStationModeConnected &wifiConnected) {
    display.displayWiFiStatus();
    display.printFooter(WiFi.SSID() + " (" + String(WiFi.RSSI()) + ")");
}

void setup() {
    Serial.begin(115200);
    Serial.println("Launching...");
    display.init();
    display.clear();
    Serial.println(readVcc());
    display.update();
    ESP8266WiFiClass::persistent(false);
    WiFi.mode(WIFI_STA);
//    WiFi.begin(ssid.c_str(), password);
//
//    while (WiFi.waitForConnectResult() != WL_CONNECTED) {
//        Serial.println("Connection Failed! Rebooting...");
//        delay(5000);
//        EspClass::restart();
//    }
    // storage.writeData();
    // storage.readData();

//    Port defaults to 8266
    // ArduinoOTA.setPort(8266);

    // Hostname defaults to esp8266-[ChipID]

    // No authentication by default
    // ArduinoOTA.setPassword("admin");

    // Password can be set with it's md5 value as well
    // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
    // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
    ArduinoOTA.onEnd([]() {
        display.clear();
        display.println("Rebooting...");
        display.update();
    });
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        uint8_t percentage = progress / (total / 100);
        display.println(" ");
        display.progressBar(percentage, "Updating: " + String(percentage) + "%");
        display.update();
    });
    ArduinoOTA.onError([](ota_error_t error) {
        display.clear();
        Serial.printf("Error[%u]: ", error);
        if (error == OTA_AUTH_ERROR) {
            display.println("Auth Failed");
        } else if (error == OTA_BEGIN_ERROR) {
            display.println(" Begin Failed ");
        } else if (error == OTA_CONNECT_ERROR) {
            display.println("Connect Failed");
        } else if (error == OTA_RECEIVE_ERROR) {
            display.println("Receive Failed");
        } else if (error == OTA_END_ERROR) {
            display.println(" End Failed ");
        }
        display.update();
        delay(1500);
        setMode(DEFAULT_MODE, true);
    });
    ArduinoOTA.begin();
    Serial.println("Ready");

//    Serial.print("IP address: ");

//    IPAddress localIp = WiFi.localIP();
//    Serial.println(localIp.toString());
//    display.println("   IP:" + localIp.toString() + "     RSSI:" + String(WiFi.RSSI()) );
//    display.update();
    WiFi.scanNetworks(true);
    display.printFooter("Scanning networks...");
    display.update();
    Serial.println("Scanning networks...");
    WiFi.onStationModeConnected(onWiFiConnect);
}

void loop() {
    int8_t foundNetworks = WiFi.scanComplete();
    if (foundNetworks >= 0) {
        Serial.printf("%d network(s) found\n", foundNetworks);
        for (uint8_t i = 0; i < foundNetworks; i++) {
            uint8_t rememberedPoint = isRemembered(WiFi.SSID(i));
            if (rememberedPoint >= 0) {
                Serial.println(wifiPoints[rememberedPoint].ssid);
                display.printFooter("Started");
                WiFi.begin(wifiPoints[rememberedPoint].ssid, wifiPoints[rememberedPoint].password);
                display.printFooter(wifiPoints[rememberedPoint].ssid);
                break;
            }
        }
        WiFi.scanDelete();
    }
    if (millis() - lastWifiStatusCheck > 10000) {
        lastWifiStatusCheck = millis();
        if (WiFi.isConnected()) {
            if (flag) {
                display.printFooter(WiFi.localIP().toString());
            } else {
                display.printFooter(WiFi.SSID() + " (" + String(WiFi.RSSI()) + ")");
            }
            flag = !flag;
        }
        display.displayWiFiStatus();
    }
    buttons.vape.tick();
    if (buttons.vape.turnH()) {
        Serial.println("hold + turn");
        Serial.println(buttons.vape.counter);  // вывести счётчик
        Serial.println(buttons.vape.fast());   // проверить быстрый поворот
        Serial.println(buttons.vape.getDir()); // направление поворота
    }
    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();
    ArduinoOTA.handle();
}