#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP32RotaryEncoder.h>

const uint8_t DI_ENCODER_A   = 33;
const uint8_t DI_ENCODER_B   = 25;
const int8_t  DI_ENCODER_SW  = -1;
const int8_t  DO_ENCODER_VCC = -1;
RotaryEncoder rotaryEncoder( DI_ENCODER_A, DI_ENCODER_B, DI_ENCODER_SW, DO_ENCODER_VCC );



#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define OLED_RESET     -1
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int switchPin = 26;
const int switchPinSwap = 27;
const int switchPinOk = 14;

String textInput = "";
String passwordInput = "";

String wifi_ssid = "";
String wifi_password = "";

int mode = 0;
bool isEnteringSSID = true;
char key[4][32] = {{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'},
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'},
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
{'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'}};
long val = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(switchPinOk, INPUT_PULLUP);
  pinMode(switchPinSwap, INPUT_PULLUP);
	rotaryEncoder.setEncoderType( EncoderType::HAS_PULLUP );
	rotaryEncoder.begin();

  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
  display.display();
  delay(2000);

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Enter WiFi SSID:");
  display.display();
  display.clearDisplay();
  display.display();
}

void loop() {

  if (isEnteringSSID) {
    handleSSID();
  }
}

bool switchOutput(int sw) {
  if (digitalRead(sw) == LOW) {
    delay(50);
    while (true){
      if (digitalRead(sw) == HIGH) {
        break;
      }
    }
    return true;
  }
  return false;
}


void handleSSID() {
  int n;
  long oldValue = 999;
  n = WiFi.scanNetworks();
  rotaryEncoder.setBoundaries( 0, n, true );
  while (true) {
    val = rotaryEncoder.getEncoderValue();
    int page = val / 4;
    if (n == 0) {
      display.setCursor(0, 0);
      display.print("No networks found.");
    } else {
      if (oldValue != val) {
        oldValue = val;
        display.clearDisplay();
        if ((page * 4) <= n) {
          for (int i = 0; i < 4; ++i) {
            // Print SSID and RSSI for each network found
            int j = (page * 4) + i;
            display.setCursor(0, (i * 17));
            if (j == n) {
              display.print("Scan Again");
            } else if (j < n){
              display.print(j + 1);
              display.print(": ");
              display.print(WiFi.SSID(j));
              display.print((WiFi.encryptionType(j) == WIFI_AUTH_OPEN) ? " " : "*");
            }
          }
          display.setCursor(120, ((val % 4) * 17));
          display.print("<");
        }
      }
      if (switchOutput(switchPin)) {
        if (val == n) {
          n = WiFi.scanNetworks();
          rotaryEncoder.setBoundaries( 0, n, true );
          rotaryEncoder.setEncoderValue(0);
        } else {
          oldValue = 999;
          wifi_ssid = WiFi.SSID(val);
          wifi_password = (WiFi.encryptionType(val) == WIFI_AUTH_OPEN) ? "" : handlePassword(wifi_ssid);
          connectToWiFi(wifi_ssid, wifi_password);
          break;
        }
      }
    }
    
    display.display();
  }
  isEnteringSSID = false;
}


String handlePassword(String ssid) {
  int okSelectCount = 0;
  long oldValue = 999;
  while (true) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("SSID: ");
    display.print(ssid.substring(0, 15));

    if (switchOutput(switchPinOk)) {
      okSelectCount += 1;
    }
    if (okSelectCount == 0) {
      display.setCursor(0, 17);
      if (switchOutput(switchPinSwap)) {
        rotaryEncoder.setEncoderValue(0);
        mode += 1;
        oldValue = 99;
      }
      val = rotaryEncoder.getEncoderValue();
      if (mode == 1) {
        rotaryEncoder.setBoundaries( 0, 25, true );
        display.print("Password(S alpha): ");
      } else if (mode == 2) {
        rotaryEncoder.setBoundaries( 0, 9, true );
        display.print("Password(Number): ");
      } else if (mode == 3) {
        rotaryEncoder.setBoundaries( 0, 31, true );
        display.print("Password(Symbol): ");
      } else {
        mode = 0;
        rotaryEncoder.setBoundaries( 0, 25, true );
        display.print("Password(B alpha): ");
      }


      if (oldValue != val) {
        oldValue = val;
        char gg = key[mode][val];
        textInput = String(gg);
      }
      if (digitalRead(switchPin) == LOW) {
        delay(50);
        rotaryEncoder.setEncoderValue(0);
        while (true){
          val = rotaryEncoder.getEncoderValue();
          if (digitalRead(switchPin) == HIGH) {
            if (val == 0) {
              passwordInput = passwordInput + textInput;
              rotaryEncoder.setEncoderValue(0);
            } else {
              String pass = passwordInput.substring(0, (passwordInput.length() - 1));
              passwordInput = pass;
            }
            break;
          }
        }
      }
      display.setCursor(0, 34);
      display.print(passwordInput);
      display.print(textInput);
    } else if (okSelectCount == 1) {
      if (switchOutput(switchPinSwap)) {
        okSelectCount -= 1;
      }
      display.setCursor(0, 17);
      display.print("Password: ");
      display.setCursor(0, 34);
      display.print(passwordInput);
    } else if (okSelectCount == 2) {
      break;
    }
    display.display();
  }
  return passwordInput;
}


void connectToWiFi(String SSID, String Password) {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Connecting to WiFi...");
  display.display();

  WiFi.begin(SSID, Password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Connected to WiFi!");
  display.display();
}