#include "integration_layer.h"
#include <string.h>

// Forward declarations for external dependencies
size_t midea_protocol_encode(const midea_control_t* control, uint8_t* buffer, size_t buffer_size);
bool midea_protocol_decode(const uint8_t* buffer, size_t buffer_size, midea_status_t* status);

/**
 * @brief Initialize the integration layer
 * @return true if initialization successful, false otherwise
 */
bool integration_layer_init(void) {
    // Initialize any required subsystems
    if (!zigbee_zcl_init()) {
        return false;
    }

    // Additional initialization would go here
    return true;
}

/**
 * @brief Deinitialize the integration layer
 * @return true if deinitialization successful, false otherwise
 */
bool integration_layer_deinit(void) {
    // Deinitialize any subsystems
    // Additional cleanup would go here
    return true;
}

/**
 * @brief Convert Zigbee ZCL attributes to Midea UART control structure
 * @param zcl_attrs Source Zigbee attributes
 * @param uart_cmd Destination UART command structure
 * @return true if conversion successful, false otherwise
 */
bool integration_layer_zigbee_to_uart(const zcl_thermostat_attrs_t* zcl_attrs,
                                     midea_control_t* uart_cmd) {
    // Validate input parameters
    if (zcl_attrs == NULL || uart_cmd == NULL) {
        return false;
    }

    // Initialize the control structure
    midea_control_init(uart_cmd);

    // Map Zigbee system mode to Midea UART mode
    switch (zcl_attrs->system_mode) {
        case 0: // Off
            uart_cmd->power_state = 0;
            uart_cmd->mode = MODE_OFF;
            break;
        case 1: // Auto
            uart_cmd->power_state = 1;
            uart_cmd->mode = MODE_AUTO;
            break;
        case 3: // Cooling
            uart_cmd->power_state = 1;
            uart_cmd->mode = MODE_COOL;
            break;
        case 4: // Heating
            uart_cmd->power_state = 1;
            uart_cmd->mode = MODE_HEAT;
            break;
        case 8: // Dry
            uart_cmd->power_state = 1;
            uart_cmd->mode = MODE_DRY;
            break;
        case 9: // Sleep
            uart_cmd->power_state = 1;
            uart_cmd->mode = MODE_SLEEP;
            break;
        default:
            // Unsupported mode, default to off
            uart_cmd->power_state = 0;
            uart_cmd->mode = MODE_OFF;
            break;
    }

    // Convert temperature from 0.01°C units to Midea format (already in 0.01°C)
    uart_cmd->target_temp = zcl_attrs->local_temperature;
    uart_cmd->temp_change = 1;

    // Indicate that mode has changed
    uart_cmd->mode_change = 1;

    // Set default fan speed
    uart_cmd->pwm_arg = 0;  // Auto fan speed

    return true;
}

/**
 * @brief Convert Midea UART control structure to Zigbee ZCL attributes
 * @param uart_cmd Source UART command structure
 * @param zcl_attrs Destination Zigbee attributes
 * @return true if conversion successful, false otherwise
 */
bool integration_layer_uart_to_zigbee(const midea_control_t* uart_cmd,
                                     zcl_thermostat_attrs_t* zcl_attrs) {
    // Validate input parameters
    if (uart_cmd == NULL || zcl_attrs == NULL) {
        return false;
    }

    // Map Midea UART mode to Zigbee system mode
    switch (uart_cmd->mode) {
        case MODE_OFF:
            zcl_attrs->system_mode = 0; // Off
            break;
        case MODE_COOL:
            zcl_attrs->system_mode = 3; // Cooling
            break;
        case MODE_HEAT:
            zcl_attrs->system_mode = 4; // Heating
            break;
        case MODE_AUTO:
            zcl_attrs->system_mode = 1; // Auto
            break;
        case MODE_DRY:
            zcl_attrs->system_mode = 8; // Dry
            break;
        case MODE_FAN:
            zcl_attrs->system_mode = 1; // Auto (fan only)
            break;
        case MODE_SLEEP:
            zcl_attrs->system_mode = 9; // Sleep
            break;
        default:
            // Unsupported mode, default to off
            zcl_attrs->system_mode = 0;
            break;
    }

    // Convert temperature from Midea format to Zigbee format (both use 0.01°C)
    zcl_attrs->local_temperature = uart_cmd->target_temp;

    // For simplicity, we'll set a default local temperature
    // In a real implementation, this would come from actual sensors
    if (zcl_attrs->local_temperature == 0) {
        zcl_attrs->local_temperature = 2500; // Default to 25.00°C
    }

    return true;
}

/**
 * @brief Handle incoming Zigbee command and convert to UART message
 * @param endpoint Zigbee endpoint
 * @param cluster_id Zigbee cluster ID
 * @param command_id Zigbee command ID
 * @param zigbee_payload Incoming Zigbee payload
 * @param zigbee_length Length of incoming payload
 * @param uart_buffer Buffer to store encoded UART message
 * @param uart_length Pointer to store length of encoded UART message
 * @return true if handling successful, false otherwise
 */
bool integration_layer_handle_zigbee_command(uint8_t endpoint, uint16_t cluster_id,
                                            uint8_t command_id, const uint8_t* zigbee_payload,
                                            uint16_t zigbee_length, uint8_t* uart_buffer,
                                            size_t* uart_length) {
    // Validate input parameters
    if (uart_buffer == NULL || uart_length == NULL) {
        return false;
    }

    // Handle the Zigbee command using the ZCL layer
    if (!zigbee_zcl_handle_command(endpoint, cluster_id, command_id,
                                  zigbee_payload, zigbee_length)) {
        return false;
    }

    // For specific commands, we need to parse the payload and convert to UART
    // This is a simplified implementation - real implementation would parse
    // various Zigbee command payloads
    if (cluster_id == 0x0201 && command_id == 0x02) {  // Setpoint set with occupancy
        if (zigbee_length >= 3) {
            // Parse simplified payload: [mode, temp_lsb, temp_msb, power]
            zcl_thermostat_attrs_t zcl_attrs;
            zcl_attrs.system_mode = zigbee_payload[0];  // Mode
            zcl_attrs.local_temperature = (zigbee_payload[2] << 8) | zigbee_payload[1];  // Temperature

            // Convert to UART format
            midea_control_t uart_cmd;
            if (integration_layer_zigbee_to_uart(&zcl_attrs, &uart_cmd)) {
                // Encode the UART command
                *uart_length = midea_protocol_encode(&uart_cmd, uart_buffer, 50);
                return (*uart_length > 0);
            }
        }
    }

    // For other commands, we'll just indicate success without generating UART traffic
    *uart_length = 0;
    return true;
}

/**
 * @brief Handle incoming UART response and update Zigbee attributes
 * @param uart_response Incoming UART response
 * @param uart_length Length of UART response
 * @param zcl_attrs Pointer to store updated Zigbee attributes
 * @return true if handling successful, false otherwise
 */
bool integration_layer_handle_uart_response(const uint8_t* uart_response,
                                           size_t uart_length,
                                           zcl_thermostat_attrs_t* zcl_attrs) {
    // Validate input parameters
    if (uart_response == NULL || zcl_attrs == NULL) {
        return false;
    }

    // Decode the UART response
    midea_status_t status;
    if (!midea_protocol_decode(uart_response, uart_length, &status)) {
        return false;
    }

    // Convert to Zigbee attributes
    return integration_layer_uart_to_zigbee(&(midea_control_t){
        .mode = status.mode,
        .target_temp = status.target_temp,
        .mode_change = 1,
        .temp_change = 1,
        .power_state = status.power_state
    }, zcl_attrs);
}

/**
 * @brief Handle schedule commands from Zigbee
 * @param command_id Schedule command ID
 * @param payload Schedule payload
 * @param payload_length Length of payload
 * @return true if handling successful, false otherwise
 */
bool integration_layer_handle_schedule_command(uint8_t command_id,
                                              const uint8_t* payload,
                                              uint16_t payload_length) {
    // Validate payload - NULL payload is only invalid if length > 0
    if (payload == NULL && payload_length > 0) {
        return false;
    }

    // Schedule command handling would go here
    // For now, we'll just acknowledge receipt of the command
    return true;
}