#include "input.h"
#include <limits.h>
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_adc/adc_oneshot.h"

static const char *TAG = "input";

static adc_oneshot_unit_handle_t s_adc_handle;
static adc_channel_t s_channel;

static void log_levels(void)
{
    ESP_LOGI(TAG, "Joystick ladder on ADC1_CH%d, levels L=%d U=%d P=%d D=%d R=%d tol=%d",
             CONFIG_JOYSTICK_ADC_CHANNEL,
             CONFIG_JOYSTICK_ADC_LEVEL_LEFT,
             CONFIG_JOYSTICK_ADC_LEVEL_UP,
             CONFIG_JOYSTICK_ADC_LEVEL_PRESS,
             CONFIG_JOYSTICK_ADC_LEVEL_DOWN,
             CONFIG_JOYSTICK_ADC_LEVEL_RIGHT,
             CONFIG_JOYSTICK_ADC_TOLERANCE);
}

void input_init(void)
{
    adc_oneshot_unit_init_cfg_t unit_cfg = {
        .unit_id = ADC_UNIT_1,
        .ulp_mode = ADC_ULP_MODE_DISABLE,
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&unit_cfg, &s_adc_handle));

    s_channel = (adc_channel_t)CONFIG_JOYSTICK_ADC_CHANNEL;
    adc_oneshot_chan_cfg_t chan_cfg = {
        .bitwidth = ADC_BITWIDTH_DEFAULT,
        .atten = ADC_ATTEN_DB_11,
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(s_adc_handle, s_channel, &chan_cfg));
    log_levels();
}

adc_channel_t input_get_channel(void)
{
    return s_channel;
}

esp_err_t input_read_raw(int *out_raw)
{
    int raw = 0;
    esp_err_t err = adc_oneshot_read(s_adc_handle, s_channel, &raw);
    if (err != ESP_OK) {
        return err;
    }
    if (out_raw) {
        *out_raw = raw;
    }
    return ESP_OK;
}

input_event_t input_poll(void)
{
    int raw = 0;
    if (input_read_raw(&raw) != ESP_OK) {
        return INPUT_NONE;
    }
    struct level_map {
        input_event_t evt;
        int expected;
    } map[] = {
        {INPUT_LEFT, CONFIG_JOYSTICK_ADC_LEVEL_LEFT},
        // Вертикаль інвертована (UP читається ближче до рівня DOWN) на цій платі
        {INPUT_UP, CONFIG_JOYSTICK_ADC_LEVEL_DOWN},
        {INPUT_CENTER, CONFIG_JOYSTICK_ADC_LEVEL_PRESS},
        {INPUT_DOWN, CONFIG_JOYSTICK_ADC_LEVEL_UP},
        {INPUT_RIGHT, CONFIG_JOYSTICK_ADC_LEVEL_RIGHT},
    };

    int best_diff = INT_MAX;
    input_event_t best_evt = INPUT_NONE;
    for (size_t i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
        int diff = map[i].expected - raw;
        if (diff < 0) {
            diff = -diff;
        }
        if (diff < best_diff) {
            best_diff = diff;
            best_evt = map[i].evt;
        }
    }

    if (best_diff <= CONFIG_JOYSTICK_ADC_TOLERANCE) {
        return best_evt;
    }
    return INPUT_NONE;
}
