/*******************************************************************************
 * @file    led_control.c
 * @brief   LED 직접 제어 드라이버 (BSP 미사용)
 * @date    2026-03-30
 *
 * app_timer 1개로 2색 LED(녹색/주황)의 복합 blink 패턴 구현
 * 단순 on/off 상태는 타이머 없이 즉시 GPIO 제어
 * 복합 패턴(에러 등)은 phase 기반 state machine으로 처리
 ******************************************************************************/

#include "led_control.h"
#include "nrf_gpio.h"
#include "app_timer.h"

/*==============================================================================
 * 내부 상수
 *============================================================================*/
#define MS_TO_TICKS(ms)     APP_TIMER_TICKS(ms)

/*==============================================================================
 * 색상
 *============================================================================*/
#define COLOR_NONE      0
#define COLOR_GREEN     1
#define COLOR_ORANGE    2

/*==============================================================================
 * 에러 패턴 상수 (No.7)
 * 3Hz 깜빡 3회 = 166ms on + 166ms off × 3 = ~1초, 이후 꺼짐 1초
 *============================================================================*/
#define ERROR_BLINK_ON_MS       166
#define ERROR_BLINK_OFF_MS      166
#define ERROR_BLINK_COUNT       3
#define ERROR_PAUSE_MS          1000

/*==============================================================================
 * 패턴 테이블 (단순 blink 용)
 *============================================================================*/
typedef struct
{
    uint32_t on_ms;         /* LED 켜짐 시간 (ms) */
    uint32_t off_ms;        /* LED 꺼짐 시간 (ms) */
    uint8_t  color;         /* COLOR_GREEN 또는 COLOR_ORANGE */
    bool     repeat;        /* true: 무한 반복, false: 1회 후 OFF */
} led_pattern_t;

static const led_pattern_t m_patterns[LED_STATE_COUNT] =
{
    [LED_STATE_OFF]              = { 0,    0,    COLOR_NONE,   false },
    [LED_STATE_POWER_ON]         = { 2000, 0,    COLOR_GREEN,  false },  /* 초록 점등 2초 → 유지 */
    [LED_STATE_POWER_OFF]        = { 2000, 0,    COLOR_GREEN,  false },  /* 초록 점등 2초 → OFF */
    [LED_STATE_ADVERTISING]      = { 1000, 1000, COLOR_GREEN,  true  },  /* 초록 점멸 1초 */
    [LED_STATE_DETACH_WARNING]   = { 1000, 3000, COLOR_GREEN,  true  },  /* 초록 1초 on / 3초 off */
    [LED_STATE_ALIGN_SEARCHING]  = { 1000, 1000, COLOR_ORANGE, true  },  /* 주황 점멸 1초 */
    [LED_STATE_ALIGN_COMPLETE]   = { 3000, 1000, COLOR_GREEN,  true  },  /* 초록 3초 on / 1초 off */
    [LED_STATE_ERROR]            = { 0,    0,    COLOR_ORANGE, true  }   /* 별도 state machine */
};

/*==============================================================================
 * 모듈 변수
 *============================================================================*/
APP_TIMER_DEF(m_led_timer);

static led_state_t  m_current_state = LED_STATE_OFF;
static bool         m_phase_on;         /* true: LED 켜진 구간, false: 꺼진 구간 */

/* 에러 패턴 전용 */
static uint8_t      m_error_blink_cnt;  /* 현재까지 깜빡인 횟수 */
static uint8_t      m_error_phase;      /* 0: blink-on, 1: blink-off, 2: pause */

/*==============================================================================
 * GPIO 헬퍼
 *============================================================================*/

static inline void led_green_on(void)
{
#if LED_ACTIVE_LOW
    nrf_gpio_pin_clear(LED_PIN_GREEN);
#else
    nrf_gpio_pin_set(LED_PIN_GREEN);
#endif
}

static inline void led_green_off(void)
{
#if LED_ACTIVE_LOW
    nrf_gpio_pin_set(LED_PIN_GREEN);
#else
    nrf_gpio_pin_clear(LED_PIN_GREEN);
#endif
}

static inline void led_orange_on(void)
{
#if LED_ACTIVE_LOW
    nrf_gpio_pin_clear(LED_PIN_ORANGE);
#else
    nrf_gpio_pin_set(LED_PIN_ORANGE);
#endif
}

static inline void led_orange_off(void)
{
#if LED_ACTIVE_LOW
    nrf_gpio_pin_set(LED_PIN_ORANGE);
#else
    nrf_gpio_pin_clear(LED_PIN_ORANGE);
#endif
}

static void led_all_off(void)
{
    led_green_off();
    led_orange_off();
}

static void led_color_on(uint8_t color)
{
    led_all_off();
    if (color == COLOR_GREEN)       led_green_on();
    else if (color == COLOR_ORANGE) led_orange_on();
}

/*==============================================================================
 * 타이머 시작 헬퍼
 *============================================================================*/
static void timer_start_ms(uint32_t ms)
{
    if (ms == 0) return;
    app_timer_start(m_led_timer, MS_TO_TICKS(ms), NULL);
}

/*==============================================================================
 * 에러 패턴 state machine (No.7)
 * phase 0: LED ON  (166ms) → phase 1
 * phase 1: LED OFF (166ms) → cnt++ → cnt<3 ? phase 0 : phase 2
 * phase 2: PAUSE   (1000ms) → cnt=0, phase 0
 *============================================================================*/
static void error_pattern_start(void)
{
    m_error_blink_cnt = 0;
    m_error_phase = 0;
    led_color_on(COLOR_ORANGE);
    timer_start_ms(ERROR_BLINK_ON_MS);
}

static void error_pattern_tick(void)
{
    switch (m_error_phase)
    {
        case 0: /* ON 구간 끝 → OFF */
            led_all_off();
            m_error_phase = 1;
            timer_start_ms(ERROR_BLINK_OFF_MS);
            break;

        case 1: /* OFF 구간 끝 */
            m_error_blink_cnt++;
            if (m_error_blink_cnt < ERROR_BLINK_COUNT)
            {
                /* 다시 ON */
                m_error_phase = 0;
                led_color_on(COLOR_ORANGE);
                timer_start_ms(ERROR_BLINK_ON_MS);
            }
            else
            {
                /* 3회 완료 → pause */
                m_error_phase = 2;
                timer_start_ms(ERROR_PAUSE_MS);
            }
            break;

        case 2: /* pause 끝 → 처음부터 */
            m_error_blink_cnt = 0;
            m_error_phase = 0;
            led_color_on(COLOR_ORANGE);
            timer_start_ms(ERROR_BLINK_ON_MS);
            break;

        default:
            break;
    }
}

/*==============================================================================
 * 타이머 콜백
 *============================================================================*/
static void led_timer_handler(void * p_context)
{
    (void)p_context;

    /* 에러 상태는 별도 처리 */
    if (m_current_state == LED_STATE_ERROR)
    {
        error_pattern_tick();
        return;
    }

    const led_pattern_t * p = &m_patterns[m_current_state];

    if (m_phase_on)
    {
        /* ON→OFF 전환 */
        led_all_off();
        m_phase_on = false;

        if (p->off_ms > 0)
        {
            timer_start_ms(p->off_ms);
        }
        else if (!p->repeat)
        {
            /* 1회성: off_ms == 0 이면 그냥 유지 (POWER_ON) 또는 끄기 (POWER_OFF) */
            if (m_current_state == LED_STATE_POWER_OFF)
            {
                led_all_off();
                m_current_state = LED_STATE_OFF;
            }
            /* POWER_ON: 점등 유지 상태 → 타이머 x */
        }
    }
    else
    {
        /* OFF → ON 전환 */
        if (p->repeat)
        {
            led_color_on(p->color);
            m_phase_on = true;
            timer_start_ms(p->on_ms);
        }
        /* repeat == false && off_ms > 0 인 경우는 현재 없음 */
    }
}

/*==============================================================================
 * 공개 함수
 *============================================================================*/

void led_init(void)
{
    /* GPIO 출력 설정 */
    nrf_gpio_cfg_output(LED_PIN_GREEN);
    nrf_gpio_cfg_output(LED_PIN_ORANGE);
    led_all_off();

    /* 타이머 생성 (single-shot) */
    app_timer_create(&m_led_timer, APP_TIMER_MODE_SINGLE_SHOT, led_timer_handler);

    m_current_state = LED_STATE_OFF;
}

void led_set_state(led_state_t state)
{
    if (state >= LED_STATE_COUNT) return;
 
    /* 이전 패턴 중단 */
    app_timer_stop(m_led_timer);
    led_all_off();

    m_current_state = state;
    m_phase_on = false;

    const led_pattern_t * p = &m_patterns[state];

    switch (state)
    {
        case LED_STATE_OFF:
            /* 이미 all off */
            break;

        /* 에러 패턴: 별도 state machine */
        case LED_STATE_ERROR:
            error_pattern_start();
            break;

        /* 그 외: on 구간부터 시작 */
        default:
            led_color_on(p->color);
            m_phase_on = true;
            if (p->on_ms > 0)
            {
                timer_start_ms(p->on_ms);
            }
            break;
    }
}

led_state_t led_get_state(void)
{
    return m_current_state;
}
