#pragma once
#include "Receiver.h"

enum class MeasureState : uint8_t { IDLE, SETTLING, RUNNING, PASS, FAIL };

class Measurement {
 public:
  explicit Measurement(PulseReceiver &receiver) : receiver_(receiver) {}
  bool start(float expectedHz, float expectedDuty, float tolerancePct,
             uint32_t testTimeMs, uint16_t averagingPeriods,
             uint8_t settleCycles, bool activeRxLightOn);
  MeasureState update();
  bool takeProgressUpdate();
  void abort();
  void forceFail(FailReason reason);
  MeasureState state() const { return state_; }
  FailReason reason() const { return stats_.reason; }
  const StageStats &stats() const { return stats_; }
  uint8_t progressStep() const { return currentStep_; }
  bool statsSnapshot(StageStats &out) const;
 private:
  static void taskEntry(void *context);
  void taskLoop();
  MeasureState processOnce();
  void fail(FailReason reason);
  void completeMeasurement();
  void publishStats();
  PulseReceiver &receiver_;
  volatile MeasureState state_ = MeasureState::IDLE;
  TaskHandle_t task_ = nullptr;
  StageStats stats_ = {};
  StageStats publishedStats_ = {};
  mutable portMUX_TYPE statsMux_ = portMUX_INITIALIZER_UNLOCKED;
  uint32_t expectedHz_ = 0;
  float expectedDutyPct_ = 0.0f, tolerancePct_ = 0.0f;
  uint8_t settleCycles_ = 0, settleLeft_ = 0;
  uint64_t measurementStartTick_ = 0, deadlineTick_ = 0, stepTicks_ = 0;
  uint32_t startedMs_ = 0, measurementStartMs_ = 0, lastPeriodMs_ = 0;
  uint32_t stepTimeMs_ = 1, expectedPeriodMs_ = 1;
  volatile uint8_t currentStep_ = 0;
  volatile bool progressUpdatePending_ = false;
  PulsePeriod periodBatch_[PERIOD_BATCH_SIZE] = {};
};
