#ifndef APP_TYPES_H
#define APP_TYPES_H

#include <stdbool.h>
#include <stdint.h>

typedef enum
{
    APP_ROLE_MASTER = 1,
    APP_ROLE_SLAVE = 0
} AppRole_t;

typedef enum
{
    APP_ZB_DISCONNECTED = 0,
    APP_ZB_JOINING,
    APP_ZB_CONNECTED,
    APP_ZB_ERROR
} AppZigbeeState_t;

typedef struct
{
    bool pressed;
    bool changed;
    uint32_t last_change_ms;
} AppButton_t;

typedef struct
{
    uint16_t raw;
    uint16_t filtered;
    uint8_t percent;
} AppAnalogChannel_t;

typedef struct
{
    AppButton_t buttons[3];
    AppAnalogChannel_t analog;
    uint32_t sequence;
} AppSlaveInputs_t;

typedef struct
{
    uint32_t sequence;
    uint8_t button_mask;
    uint16_t analog_raw;
    uint8_t analog_percent;
} AppSlaveReport_t;

typedef struct
{
    bool online;
    AppSlaveReport_t last_report;
    uint32_t last_seen_ms;
} AppMasterNode_t;

typedef struct
{
    uint16_t pan_id;
    uint8_t channel;
    uint8_t endpoint;
    uint16_t cluster_id;
} AppZigbeeConfig_t;

typedef struct
{
    AppRole_t role;
    AppZigbeeState_t zigbee_state;
    AppSlaveInputs_t slave_inputs;
    AppMasterNode_t master_node;
    AppZigbeeConfig_t zigbee;
    uint32_t uptime_ms;
    uint32_t last_report_ms;
} AppContext_t;

extern AppContext_t g_app;

extern volatile uint32_t watch_role;
extern volatile uint32_t watch_is_master;
extern volatile uint32_t watch_is_slave;
extern volatile uint32_t watch_role_pin_is_master;
extern volatile uint32_t watch_zigbee_state;
extern volatile uint32_t watch_master_online;
extern volatile uint32_t watch_master_last_seen_ms;
extern volatile uint32_t watch_master_last_sequence;
extern volatile uint32_t watch_master_button_mask;
extern volatile uint32_t watch_master_analog_raw;
extern volatile uint32_t watch_master_analog_percent;
extern volatile uint32_t watch_slave_sequence;
extern volatile uint32_t watch_slave_button_mask;
extern volatile uint32_t watch_slave_analog_raw;
extern volatile uint32_t watch_slave_analog_percent;
extern volatile uint32_t watch_report_tx_count;
extern volatile uint32_t watch_report_rx_count;
extern volatile uint32_t watch_report_tx_attempt_count;
extern volatile uint32_t watch_report_tx_ok_count;
extern volatile uint32_t watch_report_tx_busy_count;
extern volatile uint32_t watch_report_tx_confirm_count;
extern volatile uint32_t watch_report_tx_confirm_status;
extern volatile uint32_t watch_report_rx_ind_count;
extern volatile uint32_t watch_report_rx_decode_fail_count;
extern volatile uint32_t watch_report_rx_last_cluster;
extern volatile uint32_t watch_report_rx_last_length;
extern volatile uint32_t watch_zigbee_ready;
extern volatile uint32_t watch_rejoin_request_count;
extern volatile uint32_t watch_rejoin_success_count;
extern volatile uint32_t watch_rejoin_fail_count;
extern volatile uint32_t watch_rejoin_active;
extern volatile uint32_t watch_rejoin_last_status;
extern volatile uint32_t watch_report_tx_fail_streak;
extern volatile uint32_t watch_permit_join_count;
extern volatile uint32_t watch_permit_join_status;
extern volatile uint32_t watch_permit_join_duration;
extern volatile uint32_t watch_join_watchdog_count;

const char *App_RoleName(AppRole_t role);
void App_SetRole(AppRole_t role);
AppSlaveReport_t App_MakeSlaveReport(const AppSlaveInputs_t *inputs);
void App_MasterAcceptReport(const AppSlaveReport_t *report, uint32_t now_ms);
void App_DebugRefresh(uint32_t role_pin_is_master);
void App_DebugOnSlaveReportTx(const AppSlaveReport_t *report);

#endif
