#include "speech_control.h"
#include "speech_buffer_policy.h"
#include "button_gesture.h"
#include "input_sender_timing.h"
#include <cassert>
#include <deque>
int main() {
    assert(input_sender_best_effort_control("speech_progress"));
    assert(input_sender_best_effort_control("speech_stop"));
    for(const char* type:{static_cast<const char*>(nullptr),"speech_request","speech_settings_set","voice_start","approval_response"})
        assert(!input_sender_best_effort_control(type));
    SpeechBufferPolicy buffer;
    buffer.start(7056*25,7056);
    assert(!buffer.ready(25)); // Short sentences cannot underrun while receiving.
    assert(!buffer.stalled(25,3000) && buffer.stalled(25,10000));
    buffer.complete=true;assert(buffer.ready(26) && !buffer.stalled(0,5000));
    buffer.start(7056*100,7056);
    for(unsigned i=0;i<32;++i)assert(!buffer.ready(i));
    assert(buffer.ready(32) && buffer.started);
    assert(!buffer.stalled(1,10000) && buffer.stalled(0,10000));
    assert(!buffer.ready(0) && !buffer.playing);
    for(unsigned i=1;i<16;++i)assert(!buffer.ready(i));
    assert(buffer.ready(16));
    assert(!buffer.ready(0));buffer.complete=true;
    assert(buffer.ready(1)); // final partial reserve drains without waiting for 16
    assert(!buffer.ready(0) && !buffer.stalled(0,100000));
    buffer.start(7056*25,7056);assert(!buffer.playing && !buffer.complete && !buffer.started);
    SpeechStream s;
    assert(!s.start("x",48000,16,1));assert(s.start("one",44100,16,1));
    assert(s.chunk("one",0,7056));assert(!s.chunk("stale",0,7056));assert(s.id=="one");
    assert(!s.chunk("one",2,7056));assert(s.id.empty());
    assert(s.start("two",44100,16,1));assert(!s.chunk("two",0,7057));assert(s.id.empty());
    assert(s.start("three",44100,16,1));assert(s.chunk("three",0,2));
    assert(!s.end("old",1));assert(s.end("three",1));assert(!s.chunk("three",1,2));
    // Host fake-device bounded queue: cancel, never silently drop a chunk.
    std::deque<int> queue;
    assert(s.start("queue",44100,16,1));
    for (unsigned i=0;i<9;++i) {assert(s.chunk("queue",i,7056));if(queue.size()==8){queue.clear();s.stop();break;}queue.push_back(i);}
    assert(s.id.empty() && queue.empty());
    SpeechMenu menu;menu.open();assert(menu.label()=="AGENT SETTINGS");
    assert(menu.click(false)==SpeechMenuAction::AGENT_SETTINGS);
    menu.click(true);assert(menu.label()=="SPEECH");assert(menu.click(false)==SpeechMenuAction::LOAD_SPEECH);
    menu.load("AUTO_REPLY");assert(menu.mode==2);
    menu.click(false);menu.click(true);assert(menu.mode==3);assert(menu.click(false)==SpeechMenuAction::SAVE_MODE);
    menu.click(true);assert(menu.label()=="READ SCREEN NOW");assert(menu.click(false)==SpeechMenuAction::READ_SCREEN);
    menu.open();assert(menu.page==SpeechMenu::Page::ROOT);
    assert(menu.back()==SpeechMenuAction::AGENT_SETTINGS);
    menu.load("OFF");menu.open_speech();menu.click(false);menu.click(true);
    assert(menu.page==SpeechMenu::Page::MODE && menu.mode==1);
    assert(menu.back()==SpeechMenuAction::NONE && menu.page==SpeechMenu::Page::SPEECH && menu.mode==0);
    assert(menu.back()==SpeechMenuAction::AGENT_SETTINGS);
    // Long B enters settings once; releasing does not accidentally select.
    ButtonGesture b;b.update(true,0,1,true);b.update(true,30,1,true);
    assert(b.update(true,630,1,true)==Gesture::LONG);menu.open();
    b.update(false,700,2,true);assert(b.update(false,730,2,true)==Gesture::LONG_RELEASE);
    assert(menu.page==SpeechMenu::Page::ROOT);
    // Approval invalidates any in-progress menu press.
    ButtonGesture a;a.update(true,0,2,true);a.update(true,30,2,true);
    a.update(false,100,3,false);assert(a.update(false,130,3,false)==Gesture::NONE);
}
