#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>

Preferences prefs;
WebServer server(80);

// dedicated reset/setup button: wire gpio27 -> momentary button -> gnd
const int RESET_PIN = 27;
const unsigned long RESET_HOLD_MS = 1000;

// softap fallback
const char* AP_SSID = "baby-monitor-setup";
const char* AP_PASSWORD = "setup1234";

// saved / editable config
String wifi_ssid = "";
String wifi_password = "";
String dest_ip_str = "192.168.1.190";
uint16_t udp_port = 5004;
c:\Users\moses\proj\vtech\mic\mic.ino
bool config_mode = false;
const unsigned long WIFI_CONNECT_TIMEOUT_MS = 15000;

unsigned long reset_press_start = 0;
bool reset_armed = false;

String html_escape(const String& s) {
  String out = s;
  out.replace("&", "&amp;");
  out.replace("<", "&lt;");
  out.replace(">", "&gt;");
  out.replace("\"", "&quot;");
  return out;
}

void load_config() {
  prefs.begin("bmcfg", true);
  wifi_ssid = prefs.getString("ssid", "");
  wifi_password = prefs.getString("pwd", "");
  dest_ip_str = prefs.getString("destip", "192.168.1.190");
  udp_port = prefs.getUShort("port", 5004);
  prefs.end();
}

void save_config(const String& ssid, const String& pwd, const String& dest_ip, uint16_t port) {
  prefs.begin("bmcfg", false);
  prefs.putString("ssid", ssid);
  prefs.putString("pwd", pwd);
  prefs.putString("destip", dest_ip);
  prefs.putUShort("port", port);
  prefs.end();
}

void clear_config() {
  prefs.begin("bmcfg", false);
  prefs.clear();
  prefs.end();
}

bool valid_ipv4(const String& s) {
  IPAddress ip;
  return ip.fromString(s);
}

void handle_root() {
  String page =
    "<!doctype html>"
    "<html><head>"
    "<meta name='viewport' content='width=device-width,initial-scale=1'>"
    "<title>baby monitor setup</title>"
    "<style>"
    "body{font-family:sans-serif;max-width:520px;margin:2rem auto;padding:0 1rem;}"
    "input{width:100%;padding:.6rem;margin:.2rem 0 1rem 0;box-sizing:border-box;}"
    "button{padding:.7rem 1rem;margin-right:.5rem;}"
    "code{background:#eee;padding:.1rem .3rem;}"
    "</style>"
    "</head><body>"
    "<h2>baby monitor setup</h2>"
    "<p>connect to ap <code>" + String(AP_SSID) + "</code> then browse to <code>192.168.4.1</code>.</p>"
    "<form method='post' action='/save'>"
    "<label>wifi ssid</label>"
    "<input name='ssid' value='" + html_escape(wifi_ssid) + "'>"
    "<label>wifi password</label>"
    "<input name='pwd' type='password' value='" + html_escape(wifi_password) + "'>"
    "<label>destination ip</label>"
    "<input name='destip' value='" + html_escape(dest_ip_str) + "'>"
    "<label>udp port</label>"
    "<input name='port' value='" + String(udp_port) + "'>"
    "<button type='submit'>save and reboot</button>"
    "</form>"
    "<form method='post' action='/clear' onsubmit='return confirm(\"clear saved config?\");'>"
    "<button type='submit'>clear saved config</button>"
    "</form>"
    "<p><a href='/status'>view status json</a></p>"
    "</body></html>";

  server.send(200, "text/html", page);
}

void handle_status() {
  String json = "{";
  json += "\"config_mode\":" + String(config_mode ? "true" : "false") + ",";
  json += "\"ap_ssid\":\"" + String(AP_SSID) + "\",";
  json += "\"saved_ssid\":\"" + html_escape(wifi_ssid) + "\",";
  json += "\"dest_ip\":\"" + html_escape(dest_ip_str) + "\",";
  json += "\"udp_port\":" + String(udp_port);
  json += "}";

  server.send(200, "application/json", json);
}

void reboot_to_setup_mode() {
  Serial.println("clearing config and rebooting to setup mode...");
  clear_config();
  delay(250);
  ESP.restart();
}

void handle_save() {
  String new_ssid = server.arg("ssid");
  String new_pwd = server.arg("pwd");
  String new_dest = server.arg("destip");
  uint16_t new_port = (uint16_t)server.arg("port").toInt();

  if (new_ssid.length() == 0) {
    server.send(400, "text/plain", "ssid required");
    return;
  }

  if (!valid_ipv4(new_dest)) {
    server.send(400, "text/plain", "invalid destination ip");
    return;
  }

  if (new_port == 0) {
    server.send(400, "text/plain", "invalid udp port");
    return;
  }

  save_config(new_ssid, new_pwd, new_dest, new_port);

  server.send(200, "text/html",
    "<html><body><h3>saved. rebooting...</h3></body></html>");
  delay(1000);
  ESP.restart();
}

void handle_clear() {
  clear_config();
  server.send(200, "text/html",
    "<html><body><h3>config cleared. rebooting...</h3></body></html>");
  delay(1000);
  ESP.restart();
}

void start_config_ap() {
  config_mode = true;

  WiFi.disconnect(true, true);
  delay(250);

  WiFi.mode(WIFI_AP);
  WiFi.softAP(AP_SSID, AP_PASSWORD);

  IPAddress ip = WiFi.softAPIP();
  Serial.println("config ap active");
  Serial.printf("  ssid: %s\n", AP_SSID);
  Serial.printf("  pass: %s\n", AP_PASSWORD);
  Serial.printf("  ip:   %s\n", ip.toString().c_str());

  server.on("/", HTTP_GET, handle_root);
  server.on("/save", HTTP_POST, handle_save);
  server.on("/clear", HTTP_POST, handle_clear);
  server.on("/status", HTTP_GET, handle_status);
  server.begin();
}

bool try_connect_wifi() {
  if (wifi_ssid.length() == 0) {
    Serial.println("no saved wifi ssid");
    return false;
  }

  WiFi.disconnect(true, true);
  delay(250);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid.c_str(), wifi_password.c_str());

  Serial.printf("connecting to wifi: %s\n", wifi_ssid.c_str());

  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED &&
         millis() - start < WIFI_CONNECT_TIMEOUT_MS) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("connected");
    Serial.printf("  ip: %s\n", WiFi.localIP().toString().c_str());
    Serial.printf("  dest ip: %s\n", dest_ip_str.c_str());
    Serial.printf("  udp port: %u\n", udp_port);
    return true;
  }

  Serial.println("wifi connect failed");
  return false;
}

void check_reset_button() {
  bool pressed = (digitalRead(RESET_PIN) == LOW);

  if (pressed) {
    if (!reset_armed) {
      reset_armed = true;
      reset_press_start = millis();
      Serial.println("reset button pressed...");
    } else if (millis() - reset_press_start >= RESET_HOLD_MS) {
      Serial.println("reset hold met");
      reboot_to_setup_mode();
    }
  } else {
    if (reset_armed) {
      Serial.println("reset button released");
    }
    reset_armed = false;
    reset_press_start = 0;
  }
}

void setup() {
  Serial.begin(115200);
  delay(200);

  pinMode(RESET_PIN, INPUT_PULLUP);

  load_config();

  if (!try_connect_wifi()) {
    start_config_ap();
  }
}

void loop() {
  check_reset_button();

  if (config_mode) {
    server.handleClient();
    delay(2);
    return;
  }

  // placeholder for later normal-mode behavior
  static unsigned long last_print = 0;
  if (millis() - last_print > 5000) {
    Serial.printf("normal mode alive. wifi=%s ip=%s dest=%s:%u\n",
      wifi_ssid.c_str(),
      WiFi.localIP().toString().c_str(),
      dest_ip_str.c_str(),
      udp_port);
    last_print = millis();
  }

  delay(10);
}