#include "board.h"
#include "ui_state.h"
#include "button_gesture.h"
#include "approval_control.h"
#include "speech_control.h"
#include <atomic>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
using namespace wearable;
constexpr const char* TAG="host";
void ESP_LOGI(const char*,const char*,...) {}
enum class InputModal { NONE, VOICE, SETTINGS, ERROR };
InputModal s_input_modal=InputModal::NONE;
UiState s_ui;
ApprovalControl s_approval;ApprovalAction s_approval_action;
LoadedPreferences s_saved_preferences;
uint64_t s_ui_epoch=1,s_voice_serial=0,s_voice_started=0;
std::string s_settings_phase,s_settings_id,s_settings_target,s_preference_feedback,s_voice_id,s_voice_phase,s_modal_error;
std::string s_read_screen;
SpeechMenu s_speech_menu;
bool s_cloud_connected=false,s_message_visible=false;
struct {bool selected=true;} s_pi;
std::atomic<bool> s_vibration_enabled{true};
struct QuickModel {std::string id,default_effort;std::vector<std::string> efforts;};
std::vector<QuickModel> s_models;
size_t s_model_index=0,s_effort_index=0;
board_button_t s_page_click=BOARD_BUTTON_NONE;
int s_page=0;
const char* page_name(int) {return "host";}
const char* modal_name(InputModal) {return "modal";}
const char* gesture_name(Gesture) {return "gesture";}
unsigned record_start=0,record_stop=0,saves=0,remote_requests=0,voice_send=0,voice_cancel=0;
unsigned speech_requests=0;
bool record_cancelled=false;
struct {unsigned brightness=0;void setPanelBrightness(unsigned v) {brightness=v;}} s_display;
void lock_display() {}
void unlock_display() {}
void draw_status() {}
void log_modal_transition(InputModal,const char*) {}
void stop_speech() {}
bool audio_backend_record_start(uint64_t) {++record_start;return true;}
void audio_backend_record_stop(bool cancelled) {++record_stop;record_cancelled=cancelled;}
std::string new_identity(uint64_t* serial=nullptr) {if(serial) *serial=17;return "test-id";}
std::string selected_target() {return "agent:pi:retained";}
void voice_command(const char*,const char* decision) {if(std::string(decision)=="send") ++voice_send;else ++voice_cancel;}
void speech_command(const char*) {++speech_requests;}
std::string read_screen_text() {return "screen";}
void settings_command(const char*) {++remote_requests;}
void cancel_input(bool,const char*) {s_input_modal=InputModal::NONE;s_ui.close_settings();++s_ui_epoch;}
esp_err_t preferences_save(LoadedPreferences&,const DevicePreferences&) {++saves;return ESP_FAIL;}
void sync_display_page() {}
#include "shell_input.inc"
void gesture(bool a,Gesture g) {handle_gesture(a,g,s_ui_epoch+s_approval.generation,1000);}
int main() {
    s_ui.boot({});
    // Offline Long B opens local settings, with no remote request or flash write.
    gesture(false,Gesture::LONG);assert(s_input_modal==InputModal::SETTINGS && s_ui.settings_open && !remote_requests && !saves);
    gesture(false,Gesture::LONG_RELEASE);assert(s_ui.menu==Menu::Root && s_ui.index==0);
    gesture(true,Gesture::CLICK);gesture(false,Gesture::CLICK);assert(s_ui.menu==Menu::Device);
    gesture(false,Gesture::CLICK);gesture(true,Gesture::CLICK);assert(!saves && s_ui.preferences.brightness==80);
    gesture(false,Gesture::CLICK);assert(saves==1 && s_display.brightness==230 && s_preference_feedback=="APPLIED / NOT SAVED");
    gesture(false,Gesture::LONG);assert(s_input_modal==InputModal::NONE && s_ui.app==App::Watch);
    board_previous_page();assert(s_ui.app==App::Help);
    board_next_page();assert(s_ui.app==App::Watch);
    board_next_page();assert(s_ui.app==App::Agent && s_pi.selected);
    // Navigation never alters current Agent. Voice uses the existing capture path.
    s_cloud_connected=true;gesture(true,Gesture::LONG);assert(record_start==1 && s_input_modal==InputModal::VOICE);
    const auto app=s_ui.app;board_previous_page();assert(s_ui.app==app);
    gesture(true,Gesture::LONG_RELEASE);assert(record_stop==1 && !record_cancelled && s_voice_phase=="TRANSCRIBING");
    s_voice_phase="AWAITING_CONFIRMATION";gesture(true,Gesture::CLICK);assert(voice_send==1 && s_voice_phase=="SENDING" && !s_page_click);
    cancel_input(false,"host");s_input_modal=InputModal::VOICE;s_voice_phase="AWAITING_CONFIRMATION";
    gesture(false,Gesture::CLICK);assert(voice_cancel==1 && s_input_modal==InputModal::NONE);
    // Approval owns A/B regardless of the backing app and suppresses long presses.
    s_approval.receive({"approval-a","pi","command","details",0},1000);
    gesture(true,Gesture::LONG);assert(record_start==1);
    gesture(true,Gesture::CLICK);assert(s_approval_action.id=="approval-a" && s_approval_action.approve);
    s_approval.disconnect();s_approval.receive({"approval-b","pi","command","details",0},1000);
    gesture(false,Gesture::CLICK);assert(s_approval_action.id=="approval-b" && !s_approval_action.approve);
    s_approval.disconnect();
    const auto epoch=s_ui_epoch+s_approval.generation;
    handle_gesture(false,Gesture::CLICK,epoch-1,1000);assert(s_page_click==BOARD_BUTTON_NONE);
    std::puts("Production shell gestures / offline settings / Apply failure / Voice / Approval modal priority PASS (host)");
}
