#ifndef APP_CONTROLLER_H
#define APP_CONTROLLER_H

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

#include "uart_driver.h"
#include "integration_layer.h"
#include "status_monitor.h"
#include "zigbee_zcl.h"
#include "midea_protocol.h"

/**
 * @brief Top-level application configuration.
 *
 * Ties together UART, integration and status-monitor configuration so the
 * whole stack can be brought up from a single call.
 */
typedef struct {
    uart_config_t uart_config;
    status_monitor_config_t status_config;
    uint32_t command_spacing_ms;   /**< MideaUART command spacing (0 -> default 50ms) */
} app_controller_config_t;

/**
 * @brief Top-level application controller.
 *
 * Owns every subsystem and provides the two end-to-end data flows:
 *   - Home Assistant -> Zigbee -> Integration -> UART -> AC   (command path)
 *   - AC -> UART -> Status -> Integration -> Zigbee -> HA      (feedback path)
 */
typedef struct {
    uart_driver_t uart;
    integration_layer_t integration;
    status_monitor_t status_monitor;
    bool initialized;
    uint32_t commands_sent;      /**< Count of Zigbee commands forwarded to the AC */
    uint32_t status_updates;     /**< Count of AC status frames applied to ZCL */
    uint32_t recovery_count;     /**< Number of reset/recovery cycles performed */
    app_controller_config_t config;
} app_controller_t;

/**
 * @brief Initialize the full application stack.
 *
 * Brings up UART, integration layer, status monitor and the Zigbee ZCL
 * cluster. If @p config is NULL, sensible defaults are applied.
 *
 * @return true on success, false on bad args or subsystem init failure.
 */
bool app_controller_init(app_controller_t *app, const app_controller_config_t *config);

/**
 * @brief Tear down the full application stack.
 */
void app_controller_deinit(app_controller_t *app);

/**
 * @brief Command path: HA -> Zigbee -> Integration -> UART -> AC.
 *
 * Forwards an incoming Zigbee command through the integration layer, which
 * encodes and transmits the corresponding MideaUART frame with rate limiting.
 *
 * @param uart_out     Optional buffer to capture the encoded UART frame.
 * @param uart_out_len In: capacity of uart_out. Out: bytes written (0 if none).
 * @return true if the command was processed successfully.
 */
bool app_controller_process_zigbee_command(app_controller_t *app,
                                           uint8_t endpoint, uint16_t cluster_id,
                                           uint8_t command_id, const uint8_t *payload,
                                           uint16_t payload_length,
                                           uint8_t *uart_out, size_t *uart_out_len);

/**
 * @brief Feedback path: AC status frame -> Status -> Integration -> Zigbee -> HA.
 *
 * Decodes a raw MideaUART status frame, runs fault detection / watchdog
 * bookkeeping via the status monitor, and pushes the resulting attributes
 * into the Zigbee ZCL thermostat cluster.
 *
 * @param current_time Monotonic time in ms (for the watchdog).
 * @param out_attrs    Optional; receives the ZCL attributes applied.
 * @return true if the frame decoded and was applied.
 */
bool app_controller_process_ac_status(app_controller_t *app,
                                      const uint8_t *frame, size_t length,
                                      uint32_t current_time,
                                      zcl_thermostat_attrs_t *out_attrs);

/**
 * @brief Full poll cycle: request status over UART, apply it, run watchdog.
 *
 * Uses the status monitor to send a request and read a response through the
 * live UART driver. On communication failure, recovery is attempted.
 *
 * @return true on a successful poll, false on communication failure.
 */
bool app_controller_poll_status(app_controller_t *app, uint32_t current_time);

/**
 * @brief Reset all runtime state to a known-good baseline.
 *
 * Re-initializes UART and integration state and clears status-monitor error
 * counters, without dropping the configured parameters. Used by recovery.
 *
 * @return true on success.
 */
bool app_controller_reset(app_controller_t *app);

/**
 * @brief Perform recovery if the communication watchdog has tripped.
 *
 * @return true if recovery was performed, false if none was needed.
 */
bool app_controller_recover_if_needed(app_controller_t *app, uint32_t current_time);

/**
 * @brief Health check: true when comms are alive and no fault is latched.
 */
bool app_controller_is_healthy(const app_controller_t *app, uint32_t current_time);

#endif // APP_CONTROLLER_H
