int lastMqttState = 0;
uint32_t lastMqttAttemptMillis = 0;
uint32_t lastMqttConnectMillis = 0;
char lastMqttMessage[96] = "Ikke testet";

bool mqttShouldRun() {
  return mqttSettings.enabled && (inputMode == 2 || inputMode == 3) && WiFi.status() == WL_CONNECTED;
}

String mqttTopicForAddress(uint16_t address) {
  String base = String(mqttSettings.baseTopic);
  base.trim();
  while (base.endsWith("/")) base.remove(base.length() - 1);
  return base + "/" + String(address) + "/set";
}

bool parseMqttPayload(byte* payload, unsigned int length, bool &on) {
  String value;
  for (unsigned int i = 0; i < length; i++) {
    value += (char)payload[i];
  }
  value.trim();
  value.toUpperCase();

  // Windigipet-venligt:
  // 1 = OFF
  // 2 = ON
  if (value == "2" || value == "ON" || value == "TRUE" || value == "T" || value == "HIGH") {
    on = true;
    return true;
  }

  if (value == "1" || value == "0" || value == "OFF" || value == "FALSE" || value == "F" || value == "LOW") {
    on = false;
    return true;
  }

  return false;
}

bool parseMqttTopic(char* topic, int &address) {
  String t = String(topic);
  String base = String(mqttSettings.baseTopic);
  t.trim();
  base.trim();

  while (base.endsWith("/")) base.remove(base.length() - 1);
  String prefix = base + "/";
  String suffix = "/set";

  if (!t.startsWith(prefix)) return false;
  if (!t.endsWith(suffix)) return false;

  String addrText = t.substring(prefix.length(), t.length() - suffix.length());
  addrText.trim();
  if (addrText.length() == 0) return false;

  for (unsigned int i = 0; i < addrText.length(); i++) {
    if (!isDigit(addrText.charAt(i))) return false;
  }

  address = addrText.toInt();
  return address >= 1 && address <= 2044;
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  int address = 0;
  bool on = false;

  if (!parseMqttTopic(topic, address)) {
    Serial.print("MQTT ignoreret topic: ");
    Serial.println(topic);
    return;
  }

  if (!parseMqttPayload(payload, length, on)) {
    Serial.print("MQTT ignoreret payload paa topic ");
    Serial.println(topic);
    return;
  }

  handleAddressCommand("MQTT", address, on);
}

void mqttSubscribe() {
  String base = String(mqttSettings.baseTopic);
  base.trim();
  while (base.endsWith("/")) base.remove(base.length() - 1);
  String subTopic = base + "/+/set";

  if (mqttClient.subscribe(subTopic.c_str())) {
    Serial.print("MQTT subscribe: ");
    Serial.println(subTopic);
  } else {
    Serial.print("MQTT subscribe FEJLEDE: ");
    Serial.println(subTopic);
  }
}

void configureMqttClient() {
  if (mqttSettings.useTls) {
    // Praktisk til HiveMQ Cloud og andre TLS-brokere.
    // setInsecure() giver krypteret forbindelse, men uden certifikat-validering.
    // Det er nemmest til hobby/test. Senere kan vi tilføje root CA, hvis ønsket.
    if (mqttSettings.tlsInsecure) {
      secureClient.setInsecure();
      Serial.println("MQTT TLS aktiv: setInsecure() / ingen certifikat-validering");
    }
    mqttClient.setClient(secureClient);
  } else {
    mqttClient.setClient(plainClient);
    Serial.println("MQTT uden TLS aktiv");
  }
}

void setupMqtt() {
  configureMqttClient();
  mqttClient.setCallback(mqttCallback);
  mqttClient.setBufferSize(512);
  mqttClient.setKeepAlive(15);
  mqttClient.setSocketTimeout(1);   // vigtigt: MQTT maa ikke blokere DCC i lang tid

  if (!mqttShouldRun()) {
    Serial.println("MQTT ikke aktiv i denne input mode.");
    return;
  }

  mqttClient.setServer(mqttSettings.broker, mqttSettings.port);
}

void reconnectMqtt() {
  static uint32_t lastAttempt = 0;
  uint32_t now = millis();

  if (!mqttShouldRun()) return;
  if (mqttClient.connected()) return;

  // Vigtigt for DCC+MQTT:
  // En MQTT/TLS forbindelse kan blokere kortvarigt, især hvis broker/port/login er forkert.
  // Derfor forsøger vi sjældnere i DCC+MQTT, så DCC-signalet fortsat behandles stabilt.
  uint32_t retryInterval = (inputMode == 3) ? 60000UL : 10000UL;
  if (now - lastAttempt < retryInterval) return;
  lastAttempt = now;
  lastMqttAttemptMillis = now;

  configureMqttClient();
  mqttClient.setServer(mqttSettings.broker, mqttSettings.port);

  String clientId = "DCC-LysDekoder-" + String((uint32_t)ESP.getEfuseMac(), HEX);

  Serial.print("Forbinder til MQTT broker: ");
  Serial.print(mqttSettings.broker);
  Serial.print(":");
  Serial.print(mqttSettings.port);
  Serial.print("  TLS=");
  Serial.println(mqttSettings.useTls ? "ja" : "nej");

  bool ok;
  if (strlen(mqttSettings.user) > 0) {
    ok = mqttClient.connect(clientId.c_str(), mqttSettings.user, mqttSettings.password);
  } else {
    ok = mqttClient.connect(clientId.c_str());
  }

  if (ok) {
    Serial.println("MQTT forbundet");
    lastMqttConnectMillis = millis();
    lastMqttState = 0;
    strncpy(lastMqttMessage, "MQTT forbundet", sizeof(lastMqttMessage));
    lastMqttMessage[sizeof(lastMqttMessage)-1] = 0;
    mqttSubscribe();
  } else {
    lastMqttState = mqttClient.state();
    snprintf(lastMqttMessage, sizeof(lastMqttMessage), "MQTT fejl state=%d", lastMqttState);
    Serial.print("MQTT forbindelse fejlede, state=");
    Serial.println(mqttClient.state());
  }
}

void handleMqtt() {
  if (!mqttShouldRun()) return;

  if (!mqttClient.connected()) {
    reconnectMqtt();
  }

  mqttClient.loop();
}


String mqttStateText(int state) {
  switch (state) {
    case MQTT_CONNECTION_TIMEOUT: return "Timeout";
    case MQTT_CONNECTION_LOST: return "Connection lost";
    case MQTT_CONNECT_FAILED: return "Connect failed";
    case MQTT_DISCONNECTED: return "Disconnected";
    case MQTT_CONNECTED: return "Connected";
    case MQTT_CONNECT_BAD_PROTOCOL: return "Bad protocol";
    case MQTT_CONNECT_BAD_CLIENT_ID: return "Bad client ID";
    case MQTT_CONNECT_UNAVAILABLE: return "Server unavailable";
    case MQTT_CONNECT_BAD_CREDENTIALS: return "Bad credentials";
    case MQTT_CONNECT_UNAUTHORIZED: return "Unauthorized";
    default: return "State " + String(state);
  }
}

String testMqttConnectionNow() {
  if (WiFi.status() != WL_CONNECTED) {
    return "WiFi er ikke forbundet.";
  }
  if (strlen(mqttSettings.broker) == 0) {
    return "MQTT broker mangler.";
  }

  bool wasConnected = mqttClient.connected();
  if (wasConnected) mqttClient.disconnect();

  configureMqttClient();
  mqttClient.setServer(mqttSettings.broker, mqttSettings.port);
  mqttClient.setSocketTimeout(2);

  String clientId = "DCC-LysDekoder-Test-" + String((uint32_t)ESP.getEfuseMac(), HEX);
  bool ok;
  if (strlen(mqttSettings.user) > 0) {
    ok = mqttClient.connect(clientId.c_str(), mqttSettings.user, mqttSettings.password);
  } else {
    ok = mqttClient.connect(clientId.c_str());
  }

  if (!ok) {
    lastMqttState = mqttClient.state();
    snprintf(lastMqttMessage, sizeof(lastMqttMessage), "MQTT test fejl state=%d", lastMqttState);
    return "MQTT test fejlede: " + mqttStateText(lastMqttState) + " (state=" + String(lastMqttState) + ")";
  }

  String base = String(mqttSettings.baseTopic);
  base.trim();
  while (base.endsWith("/")) base.remove(base.length() - 1);
  String subTopic = base + "/+/set";
  bool subOk = mqttClient.subscribe(subTopic.c_str());
  mqttClient.disconnect();

  if (!subOk) {
    strncpy(lastMqttMessage, "MQTT test: connect OK, subscribe fejl", sizeof(lastMqttMessage));
    lastMqttMessage[sizeof(lastMqttMessage)-1] = 0;
    return "MQTT login OK, men subscribe fejlede: " + subTopic;
  }

  lastMqttState = 0;
  lastMqttConnectMillis = millis();
  strncpy(lastMqttMessage, "MQTT test OK", sizeof(lastMqttMessage));
  lastMqttMessage[sizeof(lastMqttMessage)-1] = 0;
  return "MQTT test OK. Subscribe virker: " + subTopic;
}
