#include <Arduino.h>

enum State { IDLE, SAMPLE, TRANSMIT, FAULT };
State state = IDLE;
const int SAMPLE_BUTTON=12, ACK_BUTTON=13, FAULT_RESET_BUTTON=14;
const int LEDS[] = {2, 4, 5, 18};
bool priorSample=HIGH, priorAck=HIGH, priorReset=HIGH;
unsigned long enteredAt=0;
int retries=0;

const char* stateName(State value) {
  static const char* names[] = {"IDLE", "SAMPLE", "TRANSMIT", "FAULT"};
  return names[value];
}

void enterState(State next, const char* event, const char* proof) {
  State before=state; state=next; enteredAt=millis();
  for (int i=0;i<4;i++) digitalWrite(LEDS[i], i==state);
  Serial.printf("TRANSITION %s + %s -> %s proof=%s retries=%d\n",
    stateName(before), event, stateName(state), proof, retries);
}

void reject(const char* event) {
  Serial.printf("EVENT_REJECTED state=%s event=%s reason=wrong_state\n", stateName(state), event);
}

void setup() {
  Serial.begin(115200);
  pinMode(SAMPLE_BUTTON,INPUT_PULLUP); pinMode(ACK_BUTTON,INPUT_PULLUP); pinMode(FAULT_RESET_BUTTON,INPUT_PULLUP);
  for (int pin:LEDS) pinMode(pin,OUTPUT);
  digitalWrite(LEDS[IDLE],HIGH);
  Serial.println("ESP32 STATE MACHINE READY");
  Serial.println("STATE=IDLE retries=0");
}

void loop() {
  bool s=digitalRead(SAMPLE_BUTTON), a=digitalRead(ACK_BUTTON), r=digitalRead(FAULT_RESET_BUTTON);
  if (priorSample==HIGH && s==LOW) {
    if (state==IDLE) { retries=0; enterState(SAMPLE,"EV_SAMPLE_REQUEST","sample_timer_started"); }
    else reject("EV_SAMPLE_REQUEST");
  }
  if (priorAck==HIGH && a==LOW) {
    if (state==TRANSMIT) { retries=0; enterState(IDLE,"EV_ACK_RECEIVED","message_closed"); }
    else reject("EV_ACK_RECEIVED");
  }
  if (priorReset==HIGH && r==LOW) {
    if (state==FAULT) { retries=0; enterState(IDLE,"EV_RESET","manual_reset_safe"); }
    else if (state==SAMPLE) enterState(FAULT,"EV_SAMPLE_INVALID","fault_reason_recorded");
    else reject("EV_RESET");
  }
  priorSample=s; priorAck=a; priorReset=r;

  if (state==SAMPLE && millis()-enteredAt>=500) enterState(TRANSMIT,"EV_SAMPLE_READY","message_id=42");
  if (state==TRANSMIT && millis()-enteredAt>=1200) {
    retries++;
    if (retries<3) {
      enteredAt=millis();
      Serial.printf("TRANSITION TRANSMIT + EV_TIMEOUT -> TRANSMIT proof=retry retries=%d\n",retries);
    } else enterState(FAULT,"EV_TIMEOUT","ack_timeout_radio_off");
  }
  delay(10);
}
