#include "config.h"

#define DEFAULT_VOLTAGE_READ_DELAY 1000
#define DEFAULT_MODE 0
#define VAPE_MODE 1
#define MENU_MODE 2
#define WIFI_POINTS_COUNT 4

#if defined(ESP8266)
ADC_MODE(ADC_VCC)
#endif

Graphic graphic{};

PowerController powerController{};

//TTGOClass *ttgo;
//AXP20X_Class *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"},
        {"Olya",             "27072011"},
        {"WebDev",           "devMaster#999"},
        {"Wokwi-GUEST",      ""}
};


struct {
    EncButton<EB_TICK, 14, 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;
    }
    graphic.playAnimation(animations.lowBattery);
}

void defaultAction() {
    if (isModeChanged) {
        Serial.println("Default mode enabled");
        isModeChanged = false;
        graphic.println(" ");
        readVoltageDelay = DEFAULT_VOLTAGE_READ_DELAY;
    }
    graphic.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);
    graphic.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;
    }
    graphic.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 setup() {
    Serial.begin(115200);
    Serial.println("Launching...");
//    ttgo = TTGOClass::getWatch();
//    ttgo->begin();

    graphic.init();
    graphic.display.clear();

//    power = ttgo->power;
//
//    power->adc1Enable(
//            AXP202_VBUS_VOL_ADC1 |
//            AXP202_VBUS_CUR_ADC1 |
//            AXP202_BATT_CUR_ADC1 |
//            AXP202_BATT_VOL_ADC1,
//            true);

    Serial.println(powerController.getBatteryVoltage());
    graphic.update();
    WiFi.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([]() {
        graphic.println("Rebooting...");
        graphic.update();
    });
    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        uint8_t percentage = progress / (total / 100);
        graphic.println(" ");
        graphic.progressBar(percentage, "Updating: " + String(percentage) + "%");
        graphic.update();
    });
    ArduinoOTA.onError([](ota_error_t error) {
        Serial.printf("Error[%u]: ", error);
        if (error == OTA_AUTH_ERROR) {
            graphic.println("Auth Failed");
        } else if (error == OTA_BEGIN_ERROR) {
            graphic.println(" Begin Failed ");
        } else if (error == OTA_CONNECT_ERROR) {
            graphic.println("Connect Failed");
        } else if (error == OTA_RECEIVE_ERROR) {
            graphic.println("Receive Failed");
        } else if (error == OTA_END_ERROR) {
            graphic.println(" End Failed ");
        }
        graphic.update();
        delay(1500);
        setMode(DEFAULT_MODE, true);
    });
    ArduinoOTA.begin();
    Serial.println("Ready");

//    graphic.println("   IP:" + localIp.toString() + "     RSSI:" + String(WiFi.RSSI()) );
//    graphic.update();
    WiFi.scanNetworks(true);
    graphic.printFooter("Scanning networks...");
    graphic.update();
    Serial.println("Scanning networks...");

    WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info) {
        if (event == SYSTEM_EVENT_STA_CONNECTED) {
          graphic.displayWiFiStatus();
          graphic.printFooter(WiFi.SSID() + " (" + String(WiFi.RSSI()) + ")");
            
        } else if(event == SYSTEM_EVENT_STA_GOT_IP) {
          Serial.print("IP address: ");
          IPAddress localIp = WiFi.localIP();
          Serial.println(localIp.toString());
        }
    });
}

void wifiScan() {
  int16_t foundNetworks = WiFi.scanComplete();
    if (foundNetworks >= 0) {
        Serial.printf("%d network(s) found\n", foundNetworks);
        uint16_t id = -1;
        int32_t rsii = -128;
        for (uint16_t i = 0; i < foundNetworks; i++) {
            Serial.println("Found network: " + WiFi.SSID(i));
            int32_t currentRsii = WiFi.RSSI(i);
            if (currentRsii > rsii) {
                uint8_t rememberedPoint = isRemembered(WiFi.SSID(i));
                if (rememberedPoint >= 0) {
                    rsii = currentRsii;
                    id = rememberedPoint;
                }
            }
        }
        if (id > 0) {
            Serial.println(wifiPoints[id].ssid);
            graphic.printFooter("Started");
            WiFi.begin(wifiPoints[id].ssid.c_str(), wifiPoints[id].password.c_str());
            graphic.printFooter(wifiPoints[id].ssid);
        }
        WiFi.scanDelete();
    }
}

void loop() {
    wifiScan();
    if (millis() - lastWifiStatusCheck > 10000) {
        lastWifiStatusCheck = millis();
        if (WiFi.isConnected()) {
            if (flag) {
                graphic.printFooter(WiFi.localIP().toString());
            } else {
                graphic.printFooter(WiFi.SSID() + " (" + String(WiFi.RSSI()) + ")");
            }
            flag = !flag;
        }
        graphic.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(powerController.readBatteryVoltage());
        lastVoltageRead = millis();
        graphic.printHeader(powerController.percentage, true);
        // display.printFooter("V:" + power.readableVoltage);
    }
    if (batteryLowMode == powerController.isCharged) {
        batteryLowMode = !powerController.isCharged;
        isModeChanged = true;
    }
    if (batteryLowMode) {
        batteryLow();
    } else {
        if (currentMode == VAPE_MODE) {
            vapeAction();
        } else if (currentMode == MENU_MODE) {
            menuAction();
        } else {
            defaultAction();
        }
    }
    graphic.update();
    ArduinoOTA.handle();
}