#include "approval_control.h"
#include <cassert>
#include <cstdio>
int main() {
    ApprovalControl c;
    assert(!c.modal());
    const auto old_press = c.generation;
    assert(c.receive({"one", "pi", "Edit file?", "/tmp/x", 120000}, 0));
    assert(c.release(true, old_press, 1).id.empty()); // held before overlay
    auto action = c.release(true, c.generation, 2);
    assert(action.id == "one" && action.approve);
    assert(c.release(false, c.generation, 3).id.empty()); // duplicate response is ignored
    assert(!c.finish("stale", "APPROVED", 4));
    assert(c.finish("one", "APPROVED", 4));
    assert(c.receive({"two", "codex", "Run command?", "pwd", 120000}, 5));
    assert(c.current() == nullptr && c.modal()); // one second feedback
    auto during_feedback = c.generation;
    c.tick(1004);
    assert(c.current()->id == "two");
    assert(c.release(true, during_feedback, 1005).id.empty());
    auto second = c.release(false, c.generation, 1006);
    assert(second.id == "two" && !second.approve);
    c.finish("two", "REJECTED", 1007); c.tick(2007);
    assert(!c.modal()); // page model never changed
    c.receive({"three", "pi", "Edit?", "x", 2100}, 2010);
    auto epoch=c.generation;
    assert(!c.tick(999999999) && c.modal());
    assert(c.release(true, epoch, 999999999).id == "three");
    c.finish("three", "CANCELLED", 999999999);
    c.receive({"four", "pi", "Edit?", "x", 4000}, 2200);
    c.disconnect();assert(!c.modal());
    assert(c.release(true, epoch, 2300).id.empty());

    // ---- Notification fires exactly once per approval -------------------
    // The approval gate is a Human Gate: a periodic redraw must not re-vibrate,
    // and a resolved-then-new approval must be able to notify again.
    ApprovalNotifier notifier;
    assert(!notifier.should_notify("", false));                  // nothing pending
    assert(notifier.should_notify("a1", true));                  // first time
    assert(!notifier.should_notify("a1", true));                 // periodic redraw
    assert(!notifier.should_notify("a1", true));                 // many redraws
    assert(notifier.last_notified() == "a1");
    // A queued second approval only reaches the front after the first is
    // resolved, so a new front id must notify again.
    assert(notifier.should_notify("a2", true));
    assert(!notifier.should_notify("a2", true));
    // Resolution clears the gate; later approvals still notify once.
    assert(!notifier.should_notify("", false));
    assert(notifier.should_notify("b1", true));
    assert(!notifier.should_notify("b1", true));
    // A disconnect/reset also re-arms the notifier.
    notifier.reset();
    assert(notifier.should_notify("b1", true));
    std::puts("Approval modal arbitration and exactly-once notification PASS");
}
