#!/usr/bin/env python3
"""Actual firmware hello -> actual Gateway capability expression -> UI menu."""
import ast
import json
import os
from pathlib import Path
import subprocess
import tempfile
from types import SimpleNamespace
from source_fragments import definition

repo=Path(__file__).resolve().parents[2]
cloud=(repo/'firmware/main/cloud_client.cpp').read_text()
board=(repo/'boards/m5stack_stopwatch/board.cpp').read_text()
assert 'if(name=="history")s_nav.history=true;' in board
nav=ast.parse((repo/'server/device_gateway/control/navigator.py').read_text())
capabilities=next(ast.literal_eval(node.value) for node in nav.body if isinstance(node,ast.Assign)
                  and any(isinstance(t,ast.Name) and t.id=='CAPABILITIES' for t in node.targets))
app=ast.parse((repo/'server/device_gateway/app.py').read_text())
ack=next(node for node in ast.walk(app) if isinstance(node,ast.Dict)
         and any(isinstance(v,ast.Constant) and v.value=='hello_ack' for v in node.values))
expr=next(value for key,value in zip(ack.keys,ack.values) if isinstance(key,ast.Constant) and key.value=='capabilities')
cjson=Path(os.environ.get('CJSON_DIR',repo/'.cache/esp-idf-v5.5.4/components/json/cJSON'))
with tempfile.TemporaryDirectory(prefix='history-binding-') as folder:
    temp=Path(folder)
    (temp/'send_hello.inc').write_text(definition(cloud,'send_hello'))
    (temp/'test.cpp').write_text(r'''
#include "cJSON.h"
#include "ui_state.h"
#include <cassert>
#include <cstring>
#include <iostream>
#include <string>
#define CONFIG_DEVICE_LAB_DEVICE_TOKEN "synthetic-only"
#define DEVICE_LAB_FIRMWARE_VERSION "test"
#define ESP_LOGI(...) ((void)0)
const char* s_device_id="host-test";
const char* board_slug() {return "m5stack-stopwatch";}
std::string advertised;
bool send_json(cJSON* root) {
    char* text=cJSON_PrintUnformatted(cJSON_GetObjectItemCaseSensitive(root,"capabilities"));
    advertised=text;cJSON_free(text);cJSON_Delete(root);return true;
}
#include "send_hello.inc"
int main(int argc,char** argv) {
    send_hello();
    if(argc==1) {std::cout<<advertised;return 0;}
    wearable::UiState ui;ui.boot({});ui.open_settings();ui.menu=wearable::Menu::View;
    ui.agent_capabilities(true,true,true,std::strcmp(argv[1],"history")==0);
    assert(ui.items()==3 && ui.history_available);
    ui.index=0;assert(ui.settings_click(false)==wearable::UiEffect::Current);
    ui.index=1;assert(ui.settings_click(false)==wearable::UiEffect::History);std::cout<<"Production hello / Gateway handshake / History menu binding PASS\n";
}
''')
    subprocess.run(['cc','-c',str(cjson/'cJSON.c'),'-I',str(cjson),'-o',str(temp/'cjson.o')],check=True)
    binary=temp/'test'
    subprocess.run(['c++','-std=c++17','-Wall','-Wextra','-Werror','-I',str(temp),'-I',str(cjson),
                    '-I',str(repo/'boards/common/include'),str(temp/'test.cpp'),str(temp/'cjson.o'),'-o',str(binary)],check=True)
    names=json.loads(subprocess.check_output([str(binary)],text=True))
    assert {'speech_playback','speech-buffer-v1','view-pagination'} <= set(names)
    received=eval(compile(ast.Expression(expr),'<production hello_ack>','eval'),
                  {'CAPABILITIES':capabilities,'device':SimpleNamespace(capabilities=set(names)),'sorted':sorted})
    assert 'history' in received,'Firmware hello omitted history or Gateway filtered it'
    subprocess.run([str(binary),'history'],check=True)
