// Network settings: renderer row order -> reducer index -> effect, plus the
// explicit Wi-Fi Setup confirmation.
//
// Codex found the renderer and the reducer disagreed about the Network rows:
// the screen showed [Current Network, Wi-Fi Setup, Known Networks, Back] while
// the reducer treated index 0 as "start the AP". Selecting the read-only
// "Current Network" row therefore launched the SoftAP. This test derives the
// labels from the ACTUAL renderer and asserts each index maps to the effect the
// visible row implies, so the two can never drift apart again.
#include "wearable_renderer.h"
#include "ui_state.h"

#include <cassert>
#include <cstdio>
#include <string>
#include <vector>

namespace {

// Minimal graphics probe that records the rendered row strings in order.
struct Probe {
    int line_height = 16;
    std::vector<std::string> strings;
    void setTextColor(unsigned, unsigned) {}
    void setTextDatum(int) {}
    int fontHeight() const { return line_height; }
    int textWidth(const char *t) const { return int(std::char_traits<char>::length(t)) * 8; }
    void drawString(const char *t, int, int) { strings.emplace_back(t ? t : ""); }
    void fillRoundRect(int, int, int, int, int, unsigned) {}
    void drawRoundRect(int, int, int, int, int, unsigned) {}
    void fillRect(int, int, int, int, unsigned) {}
    void drawRect(int, int, int, int, unsigned) {}
    void fillTriangle(int, int, int, int, int, int, uint16_t) {}
};
struct Fonts {
    template <class Gfx>
    void apply(Gfx &g, wearable::TypeRole, wearable::TextSize, unsigned, unsigned = 0) const {
        g.line_height = 16;
    }
};

// Render the settings body for the current menu and return every visible or
// scrolled-into-view row label (covers the small viewport window).
std::vector<std::string> render_rows(wearable::UiState &ui, wearable::ShellView &view) {
    // Try every index so the whole row set is captured regardless of scrolling.
    std::vector<std::string> all;
    const size_t count = ui.items();
    for (size_t index = 0; index < count; ++index) {
        ui.index = uint8_t(index);
        Probe probe;
        Fonts fonts;
        wearable::ShellRenderer<Probe, Fonts>(probe, fonts, ui, view).settings();
        for (const auto &s : probe.strings) {
            bool seen = false;
            for (const auto &existing : all)
                if (existing == s) { seen = true; break; }
            if (!seen) all.push_back(s);
        }
    }
    return all;
}

bool contains(const std::vector<std::string> &rows, const std::string &needle) {
    for (const auto &row : rows)
        if (row.find(needle) != std::string::npos) return true;
    return false;
}

}  // namespace

int main() {
    wearable::UiState ui;
    ui.boot({});
    ui.open_settings();
    wearable::ShellView view;
    view.wifi_state = "CONNECTED";
    view.wifi_ssid_detail = "Home-WiFi";

    // ---- The rendered Network rows, in renderer order --------------------
    ui.menu = wearable::Menu::Network;
    ui.index = 0;
    const auto network_rows = render_rows(ui, view);
    // Index 0 is the read-only current-network/status row.
    assert(contains(network_rows, "Network"));
    assert(contains(network_rows, "Wi-Fi Setup"));
    assert(contains(network_rows, "Known Networks"));
    assert(contains(network_rows, "Back"));

    // ---- Reducer mapping must match the renderer, index for index --------
    // 0 Current Network -> read-only, NO destructive action.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::Network;
        s.index = 0;
        assert(s.settings_click(false) == wearable::UiEffect::None);
        assert(s.menu == wearable::Menu::Network);  // did not start the AP
    }
    // 1 Wi-Fi Setup -> open the confirmation screen, NOT start the AP yet.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::Network;
        s.index = 1;
        assert(s.settings_click(false) == wearable::UiEffect::WifiSetupConfirm);
        assert(s.menu == wearable::Menu::WifiSetupConfirm);
    }
    // 2 Known Networks -> open the list.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::Network;
        s.index = 2;
        assert(s.settings_click(false) == wearable::UiEffect::None);
        assert(s.menu == wearable::Menu::KnownNetworks);
    }
    // 3 Back -> leave Network.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::Network;
        s.index = 3;
        assert(s.settings_click(false) == wearable::UiEffect::None);
        assert(s.menu == wearable::Menu::Root);
    }

    // ---- Explicit confirmation screen ------------------------------------
    // The visible A CANCEL / B START shortcuts act directly.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::WifiSetupConfirm;
        s.index = 0;
        Probe probe;
        Fonts fonts;
        wearable::ShellRenderer<Probe, Fonts>(probe, fonts, s, view).settings();
        bool start = false, cancel = false, prompt = false;
        for (const auto &line : probe.strings) {
            if (line.find("START WIFI SETUP?") != std::string::npos) prompt = true;
            if (line.find("B START") != std::string::npos) start = true;
            if (line.find("A CANCEL") != std::string::npos) cancel = true;
        }
        assert(prompt && start && cancel);
    }
    // One A cancels immediately. A fresh confirmation's B emits WifiSetup.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::WifiSetupConfirm;
        s.index = 0;
        assert(s.settings_click(true) == wearable::UiEffect::None);
        assert(s.menu == wearable::Menu::Network);  // cancelled, no AP
        assert(s.index == 1);  // keep Wi-Fi Setup selected

        s.menu = wearable::Menu::WifiSetupConfirm;
        s.index = 0;
        assert(s.settings_click(false) == wearable::UiEffect::WifiSetup);
    }
    // Backing out of the confirmation returns to Network, never starts the AP.
    {
        wearable::UiState s;
        s.boot({});
        s.open_settings();
        s.menu = wearable::Menu::WifiSetupConfirm;
        assert(s.settings_back() == wearable::UiEffect::None);
        assert(s.menu == wearable::Menu::Network);
    }

    std::puts("Network menu: renderer order == reducer mapping, Wi-Fi Setup "
              "requires explicit confirmation PASS (host)");
    return 0;
}
