// Host tests for mailbox/detect.h - run: g++ -std=c++11 -Wall -I mailbox test/test_detect.cpp -o /tmp/td && /tmp/td
#include <cstdio>
#include "detect.h"
static int fails = 0;
#define CHECK(c, msg) do { if (!(c)) { printf("FAIL: %s\n", msg); fails++; } else printf("ok   %s\n", msg); } while (0)

int main() {
  Detector d; det_init(&d);
  // calibration: empty box, beam delta ~400 counts each
  for (int i = 0; i < 8; i++) det_calibrate_sample(&d, 900, 500, 880, 480);
  CHECK(det_calibrate_done(&d), "calibration completes after 8 good samples");
  CHECK(d.base[0] >= 390 && d.base[0] <= 410 && d.base[1] >= 390 && d.base[1] <= 410, "baselines ~400");
  CHECK(det_update(&d, 900, 500, 880, 480) == MAIL_NO, "clear beams -> no mail");
  // one blocked reading is not enough (debounce)
  CHECK(det_update(&d, 900, 880, 880, 480) == MAIL_NO, "1 blocked reading: still no mail (debounce)");
  CHECK(det_update(&d, 900, 880, 880, 480) == MAIL_YES, "2 blocked readings in a row: MAIL");
  // in-between delta (30% of base) holds the current state (hysteresis)
  CHECK(det_update(&d, 900, 780, 880, 480) == MAIL_YES, "30% delta holds MAIL (hysteresis)");
  CHECK(det_update(&d, 900, 780, 880, 480) == MAIL_YES, "30% delta still holds MAIL");
  // clear again needs 2 readings
  CHECK(det_update(&d, 900, 500, 880, 480) == MAIL_YES, "1 clear reading: still MAIL");
  CHECK(det_update(&d, 900, 500, 880, 480) == MAIL_NO, "2 clear readings: no mail");
  // only the BACK beam blocked -> mail
  det_update(&d, 900, 500, 880, 860);
  CHECK(det_update(&d, 900, 500, 880, 860) == MAIL_YES, "back beam alone blocked -> MAIL");
  det_update(&d, 900, 500, 880, 480); det_update(&d, 900, 500, 880, 480);
  // sunlight floods sensor 1 (dark reading very low) -> keep state, report unsure
  CHECK(det_update(&d, 60, 40, 880, 480) == MAIL_NO, "flooded sensor keeps previous state (no mail)");
  CHECK(d.last_flooded == 1, "flooded reading is flagged");
  det_update(&d, 900, 880, 880, 480); det_update(&d, 900, 880, 880, 480);   // now MAIL
  CHECK(det_update(&d, 50, 45, 50, 45) == MAIL_YES, "both flooded keeps previous state (mail)");
  // dead LEDs at calibration -> calibration refuses
  Detector bad; det_init(&bad);
  for (int i = 0; i < 8; i++) det_calibrate_sample(&bad, 900, 890, 880, 875);
  CHECK(!det_calibrate_done(&bad), "calibration refuses a tiny delta (LEDs not reaching)");
  // flooded samples don't count toward calibration
  Detector sun; det_init(&sun);
  for (int i = 0; i < 8; i++) det_calibrate_sample(&sun, 40, 30, 40, 30);
  CHECK(!det_calibrate_done(&sun), "calibration ignores flooded samples");
  // slow baseline tracking only while clear, and never jumps on a blocked reading
  Detector t; det_init(&t); for (int i = 0; i < 8; i++) det_calibrate_sample(&t, 900, 500, 880, 480);
  for (int i = 0; i < 64; i++) det_update(&t, 900, 540, 880, 520);   // LEDs/dirt -> delta 360
  CHECK(t.base[0] < 400 && t.base[0] > 355, "baseline drifts slowly toward 360 while clear");
  printf(fails ? "\n%d FAILED\n" : "\nALL PASS\n", fails);
  return fails != 0;
}
