#include "midea_protocol.h"
#include <unity.h>

void setUp(void) {
    // Set up test fixtures before each test
}

void tearDown(void) {
    // Clean up test fixtures after each test
}

void test_midea_control_init(void) {
    midea_control_t control;
    midea_control_init(&control);

    // Check initial values
    TEST_ASSERT_EQUAL_INT8(MODE_OFF, control.mode);
    TEST_ASSERT_EQUAL_INT16(0, control.target_temp);
    TEST_ASSERT_EQUAL_INT8(0, control.mode_change);
    TEST_ASSERT_EQUAL_INT8(0, control.temp_change);
    TEST_ASSERT_EQUAL_INT8(0, control.power_state);
}

void test_midea_control_set_mode(void) {
    midea_control_t control;
    midea_control_init(&control);

    midea_control_set_mode(&control, MODE_COOL);

    TEST_ASSERT_EQUAL_INT8(MODE_COOL, control.mode);
    TEST_ASSERT_EQUAL_INT8(1, control.mode_change);
}

void test_midea_control_set_temperature(void) {
    midea_control_t control;
    midea_control_init(&control);

    midea_control_set_temperature(&control, 25.5f);

    // 25.5°C * 100 = 2550
    TEST_ASSERT_EQUAL_INT16(2550, control.target_temp);
    TEST_ASSERT_EQUAL_INT8(1, control.temp_change);
}

void test_midea_control_set_power(void) {
    midea_control_t control;
    midea_control_init(&control);

    midea_control_set_power(&control, true);
    TEST_ASSERT_EQUAL_INT8(1, control.power_state);

    midea_control_set_power(&control, false);
    TEST_ASSERT_EQUAL_INT8(0, control.power_state);
}

void test_midea_protocol_encode_decode(void) {
    midea_control_t control;
    midea_control_init(&control);

    // Set up a control command
    midea_control_set_mode(&control, MODE_COOL);
    midea_control_set_temperature(&control, 24.0f);
    midea_control_set_power(&control, true);
    control.mode_change = 1;
    control.temp_change = 1;

    uint8_t buffer[50];
    size_t encoded_len = midea_protocol_encode(&control, buffer, sizeof(buffer));

    // Check that we got a reasonable length
    TEST_ASSERT_GREATER_THAN(6, encoded_len);  // Minimum packet size

    // Check header
    TEST_ASSERT_EQUAL_UINT8(0xAA, buffer[0]);
    TEST_ASSERT_EQUAL_UINT8(0x55, buffer[1]);

    // Decode the message
    midea_status_t status;
    TEST_ASSERT_TRUE(midea_protocol_decode(buffer, encoded_len, &status));

    // Check decoded values
    TEST_ASSERT_EQUAL_INT8(MODE_COOL, status.mode);
    TEST_ASSERT_EQUAL_INT8(1, status.power_state);
    TEST_ASSERT_EQUAL_INT16(2400, status.target_temp);  // 24.0°C * 100
}

void test_midea_protocol_modes(void) {
    const midea_mode_t modes[] = {MODE_OFF, MODE_COOL, MODE_HEAT, MODE_AUTO, MODE_DRY, MODE_FAN, MODE_SLEEP, MODE_TURBO};
    const char* mode_names[] = {"OFF", "COOL", "HEAT", "AUTO", "DRY", "FAN", "SLEEP", "TURBO"};

    for (int i = 0; i < 8; i++) {
        midea_control_t control;
        midea_control_init(&control);

        midea_control_set_mode(&control, modes[i]);
        midea_control_set_temperature(&control, 22.0f);
        midea_control_set_power(&control, true);

        uint8_t buffer[50];
        size_t encoded_len = midea_protocol_encode(&control, buffer, sizeof(buffer));

        TEST_ASSERT_GREATER_THAN(6, encoded_len);

        midea_status_t status;
        TEST_ASSERT_TRUE(midea_protocol_decode(buffer, encoded_len, &status));

        TEST_ASSERT_EQUAL_INT8(modes[i], status.mode);
    }
}

void test_midea_protocol_temperature_precision(void) {
    float test_temps[] = {16.0f, 16.5f, 22.0f, 25.5f, 30.0f};
    int16_t expected_values[] = {1600, 1650, 2200, 2550, 3000};  // * 100

    for (int i = 0; i < 5; i++) {
        midea_control_t control;
        midea_control_init(&control);

        midea_control_set_temperature(&control, test_temps[i]);
        TEST_ASSERT_EQUAL_INT16(expected_values[i], control.target_temp);
    }
}

void test_midea_protocol_null_pointers(void) {
    // Test encoding with NULL control
    size_t len = midea_protocol_encode(NULL, NULL, 0);
    TEST_ASSERT_EQUAL_UINT(0, len);

    // Test decoding with NULL buffer
    midea_status_t status;
    TEST_ASSERT_FALSE(midea_protocol_decode(NULL, 10, &status));

    // Test decoding with NULL status
    uint8_t dummy_buffer[10] = {0};
    TEST_ASSERT_FALSE(midea_protocol_decode(dummy_buffer, 10, NULL));
}

void test_midea_protocol_buffer_limits(void) {
    midea_control_t control;
    midea_control_init(&control);
    midea_control_set_mode(&control, MODE_COOL);
    midea_control_set_temperature(&control, 25.0f);

    // Test with too small buffer
    uint8_t small_buffer[5];
    size_t len = midea_protocol_encode(&control, small_buffer, sizeof(small_buffer));
    TEST_ASSERT_EQUAL_UINT(0, len);
}

int main(void) {
    UNITY_BEGIN();

    RUN_TEST(test_midea_control_init);
    RUN_TEST(test_midea_control_set_mode);
    RUN_TEST(test_midea_control_set_temperature);
    RUN_TEST(test_midea_control_set_power);
    RUN_TEST(test_midea_protocol_encode_decode);
    RUN_TEST(test_midea_protocol_modes);
    RUN_TEST(test_midea_protocol_temperature_precision);
    RUN_TEST(test_midea_protocol_null_pointers);
    RUN_TEST(test_midea_protocol_buffer_limits);

    return UNITY_END();
}