#pragma once
#include "device_preferences.h"
#include <algorithm>
#include <array>
#include <string>
#include <vector>

namespace wearable {
enum class App : uint8_t { Watch, Agent, Monitor, Help };
enum class Menu : uint8_t { Root, Agent, View, Device, Display, Network, KnownNetworks, WifiSetupConfirm, System, Edit };
enum class Field : uint8_t { Brightness, Volume, Vibration, Touch, HomeScreen, Text, Theme, VoiceSend };
enum class UiEffect { None, CloseSettings, Apply, AgentSettings, SpeechSettings, SessionPicker, EffortSettings, PermissionSettings, VoiceSendSettings, Current, History, WifiSetupConfirm, WifiSetup, ForgetAllPending, ForgetNetwork, ForgetAll };
struct UiState {
    App app=App::Watch;
    size_t text_page=0;
    Menu menu=Menu::Root, editor_parent=Menu::Device;
    Field field=Field::Brightness;
    uint8_t index=0;
    std::array<UiEffect,8> agent_actions{UiEffect::AgentSettings,UiEffect::VoiceSendSettings,UiEffect::SpeechSettings,UiEffect::None};
    uint8_t agent_count=4;
    void agent_capabilities(bool catalog,bool effort,bool permissions,bool history=false) {
        agent_count=0;
        if(catalog)agent_actions[agent_count++]=UiEffect::SessionPicker;
        agent_actions[agent_count++]=UiEffect::AgentSettings;
        if(effort)agent_actions[agent_count++]=UiEffect::EffortSettings;
        if(permissions)agent_actions[agent_count++]=UiEffect::PermissionSettings;
        agent_actions[agent_count++]=UiEffect::VoiceSendSettings;
        // History is offered only when the selected Agent exposes it.
        history_available=history;
        agent_actions[agent_count++]=UiEffect::SpeechSettings;agent_actions[agent_count++]=UiEffect::None;
        if(menu==Menu::Agent && index>=agent_count)index=0;
    }
    static const char* agent_label(UiEffect effect) {
        switch(effect) {
        case UiEffect::SessionPicker:return "Session";
        case UiEffect::AgentSettings:return "Model";
        case UiEffect::EffortSettings:return "Effort";
        case UiEffect::PermissionSettings:return "Permissions";
        case UiEffect::VoiceSendSettings:return "Voice Send";
        case UiEffect::History:return "History";
        case UiEffect::SpeechSettings:return "Speech";
        default:return "Back";
        }
    }
    bool history_available=false;
    bool settings_open=false;
    DevicePreferences preferences, draft;
    void boot(DevicePreferences p) { preferences=draft=p; app=App(uint8_t(p.home_screen)); }
    void navigate(bool a) {
        if(settings_open) return;
        text_page=0;
        // Four immediate pages; metric details have no physical entry point.
        app=App((uint8_t(app)+(a?1:3))%4);
    }
    void open_settings() { settings_open=true; menu=Menu::Root;index=0;draft=preferences;forget_confirm=false; }
    void close_settings() { settings_open=false; draft=preferences; }
    UiEffect settings_back() {
        if(!settings_open) return UiEffect::None;
        draft=preferences;index=0;forget_confirm=false;
        if(menu==Menu::Root) {close_settings();return UiEffect::CloseSettings;}
        // Backing out of the Wi-Fi Setup confirmation returns to Network.
        if(menu==Menu::WifiSetupConfirm) {menu=Menu::Network;return UiEffect::None;}
        menu=menu==Menu::Edit?editor_parent:
             (menu==Menu::KnownNetworks?Menu::Network:Menu::Root);
        return UiEffect::None;
    }
    uint8_t items() const {
        switch(menu) {
        case Menu::Root:return 7;
        case Menu::View:return 3;
        case Menu::Agent:return agent_count;
        case Menu::Device:return 5;
        case Menu::Display:return 5;
        case Menu::Network:return 4;
        case Menu::KnownNetworks:return known_count+2; // SSIDs + Forget All + Back
        case Menu::WifiSetupConfirm:return 2;          // START / CANCEL
        case Menu::System:return 5;
        default:return 1;
        }
    }
    // Known Networks list, populated by the board before rendering. Never holds
    // a password.
    static constexpr size_t KNOWN_MAX=6;
    std::array<std::string,KNOWN_MAX> known{};
    uint8_t known_count=0;
    // Two-step confirmation for "Forget All", which is destructive.
    bool forget_confirm=false;
    void set_known(const std::vector<std::string>& ssids) {
        known_count=uint8_t(std::min(ssids.size(),KNOWN_MAX));
        for(size_t i=0;i<known_count;++i) known[i]=ssids[i];
        forget_confirm=false;
        if(menu==Menu::KnownNetworks && index>=items()) index=0;
    }
    void edit_next() {
        switch(field) {
        case Field::Brightness:draft.brightness=draft.brightness>=100?10:(draft.brightness/10+1)*10;break;
        case Field::Volume:draft.volume=draft.volume>=100?0:(draft.volume/10+1)*10;break;
        case Field::Vibration:draft.vibration_enabled=!draft.vibration_enabled;break;
        case Field::Touch:draft.touch_enabled=!draft.touch_enabled;break;
        case Field::HomeScreen:draft.home_screen=Home((uint8_t(draft.home_screen)+1)%3);break;
        case Field::Text:draft.text_size=TextSize((uint8_t(draft.text_size)+1)%3);break;
        case Field::Theme:draft.theme=Theme((uint8_t(draft.theme)+1)%2);break;
        case Field::VoiceSend:draft.voice_send_mode=VoiceSendMode((uint8_t(draft.voice_send_mode)+1)%2);break;
        }
    }
    UiEffect settings_click(bool a) {
        if(!settings_open) return UiEffect::None;
        if(menu==Menu::Edit) {
            if(a) edit_next();
            else {preferences=draft;menu=editor_parent;index=0;return UiEffect::Apply;}
            return UiEffect::None;
        }
        if(menu==Menu::WifiSetupConfirm) {
            // Match the visible shortcuts: B START, A CANCEL.
            menu=Menu::Network;index=1;
            return a?UiEffect::None:UiEffect::WifiSetup;
        }
        if(a) {index=(index+1)%items();forget_confirm=false;return UiEffect::None;}
        const auto selected=index;
        if(menu==Menu::Root) {
            if(selected==6) {close_settings();return UiEffect::CloseSettings;}
            // Root order: Agent, View, Device, Display, Network, System, Back.
            static const Menu root_map[]={Menu::Agent,Menu::View,Menu::Device,Menu::Display,Menu::Network,Menu::System};
            menu=root_map[selected];index=0;
        } else if(menu==Menu::KnownNetworks) {
            const uint8_t forget_all=known_count;
            const uint8_t back=known_count+1;
            if(selected==back) {menu=Menu::Network;index=0;forget_confirm=false;return UiEffect::None;}
            if(selected==forget_all) {
                // Destructive: require an explicit second confirmation.
                if(!forget_confirm) {forget_confirm=true;return UiEffect::ForgetAllPending;}
                forget_confirm=false;
                return UiEffect::ForgetAll;
            }
            return UiEffect::ForgetNetwork;
        } else if(selected==items()-1) {menu=menu==Menu::Network?Menu::Root:Menu::Root;index=0;}
        else if(menu==Menu::Agent) {
            if(agent_actions[selected]==UiEffect::VoiceSendSettings) {
                editor_parent=Menu::Agent;field=Field::VoiceSend;draft=preferences;menu=Menu::Edit;index=0;return UiEffect::None;
            }
            return agent_actions[selected];
        }
        else if(menu==Menu::View) {
            return selected==0?UiEffect::Current:UiEffect::History;
        }
        else if(menu==Menu::Network) {
            // Renderer order (see wearable_renderer.h):
            //   0 Current Network / Status  (read-only, no destructive action)
            //   1 Wi-Fi Setup               (explicit confirmation screen)
            //   2 Known Networks            (open the list)
            //   3 Back
            // The reducer must match the renderer index-for-index, or the device
            // acts on the wrong row (the B2 bug: selecting "Current Network"
            // started the AP).
            if(selected==0) return UiEffect::None;                       // read-only
            if(selected==1) {menu=Menu::WifiSetupConfirm;index=0;return UiEffect::WifiSetupConfirm;}
            if(selected==2) {menu=Menu::KnownNetworks;index=0;return UiEffect::None;}
            menu=Menu::Root;index=0;
        }
        else if(menu==Menu::Device || menu==Menu::Display) {
            if(menu==Menu::Display && selected==3) return UiEffect::None; // One watchface, read-only.
            editor_parent=menu; field=menu==Menu::Device?Field(selected):Field(uint8_t(Field::HomeScreen)+selected);
            draft=preferences;menu=Menu::Edit;index=0;
        }
        return UiEffect::None;
    }
};
inline const char* home_name(Home h) {return h==Home::Watch?"Watch":h==Home::Agent?"Agent":"Monitor";}
inline const char* text_name(TextSize t) {return t==TextSize::Compact?"Compact":t==TextSize::Normal?"Normal":"Large";}
inline const char* theme_name(Theme t) {return t==Theme::Dark?"Dark":"Dim";}
struct Palette {uint16_t primary,secondary,accent,done,failed,approval,selected;};
inline Palette palette(Theme t) {
    return t==Theme::Dark?Palette{0xf7be,0xa556,0x5edf,0x6ef2,0xfbae,0xfdcc,0x10c3}:
        Palette{0xce7a,0x94b3,0x8dd8,0x95d3,0xcc93,0xc550,0x1082};
}
} // namespace wearable
