#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
#include <SPI.h>
#include <MFRC522.h>
#include <HTTPClient.h>

#define SS_PIN 21
#define RST_PIN 22

const char* ssid = "NICU";
const char* password = "12345678";

// Update this to your KSWEB host URL/path.
// Example if project folder is htdocs/nicu-scaner:
// http://192.168.4.2/nicu-scaner/api/ingest_scan.php
String ingestUrl = "http://192.168.137.1/scaner/api/ingest_scan.php";

WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
MFRC522 mfrc522(SS_PIN, RST_PIN);

String webpage = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>ESP RFID Scanner</title>
</head>
<body style="font-family:Arial;text-align:center;margin-top:50px;">
  <h2>ESP32 RFID Scanner</h2>
  <h3>Waiting for card...</h3>
  <div id="result" style="font-size:22px;color:green;">No Card</div>

<script>
  var socket = new WebSocket("ws://" + location.hostname + ":81/");
  socket.onmessage = function(event) {
    document.getElementById("result").innerHTML = event.data;
  };
</script>
</body>
</html>
)rawliteral";

unsigned long lastReadAt = 0;
String lastUid = "";

String toUidString(MFRC522::Uid* uidData) {
  String uid = "";
  for (byte i = 0; i < uidData->size; i++) {
    if (uidData->uidByte[i] < 0x10) uid += "0";
    uid += String(uidData->uidByte[i], HEX);
  }
  uid.toUpperCase();
  return uid;
}

bool shouldProcessUid(const String& uid) {
  unsigned long now = millis();
  bool isDuplicate = (uid == lastUid) && ((now - lastReadAt) < 1200);
  if (isDuplicate) return false;
  lastUid = uid;
  lastReadAt = now;
  return true;
}

void postScanToServer(const String& uid) {
  if (WiFi.status() != WL_CONNECTED) return;

  HTTPClient http;
  http.begin(ingestUrl);
  http.addHeader("Content-Type", "application/json");

  String body = "{\"uid\":\"" + uid + "\",\"device_name\":\"esp32-rfid\"}";
  int code = http.POST(body);

  Serial.print("HTTP ingest status: ");
  Serial.println(code);

  if (code > 0) {
    String resp = http.getString();
    Serial.println(resp);
  }

  http.end();
}

void setup() {
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  IPAddress localIp(192, 168, 137, 50);
  IPAddress gateway(192, 168, 137, 1);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress dns(192, 168, 137, 1);
  if (!WiFi.config(localIp, gateway, subnet, dns)) {
    Serial.println("STA config failed");
  }
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(300);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("STA IP: ");
  Serial.println(WiFi.localIP());

  server.on("/", []() {
    server.send(200, "text/html", webpage);
  });
  server.begin();

  webSocket.begin();

  SPI.begin(18, 19, 23, 21);
  mfrc522.PCD_Init();
}

void loop() {
  server.handleClient();
  webSocket.loop();

  if (!mfrc522.PICC_IsNewCardPresent()) return;
  if (!mfrc522.PICC_ReadCardSerial()) return;

  String uid = toUidString(&mfrc522.uid);

  if (!shouldProcessUid(uid)) {
    mfrc522.PICC_HaltA();
    mfrc522.PCD_StopCrypto1();
    return;
  }

  int clients = webSocket.connectedClients();
  if (clients > 0) {
    webSocket.broadcastTXT(uid);
    Serial.println("WS broadcast UID: " + uid);
  } else {
    Serial.println("No WS clients, sending HTTP fallback UID: " + uid);
    postScanToServer(uid);
  }

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}
