#include "menu.h"
#include "segment.h"
#include "clock_manager.h"

// Время удержания кнопки (мс), после которого нажатие считается "длинным"
// Используется для входа в меню из режима часов
#define LONG_PRESS_MS       500

// Задержка перед началом автоповтора (мс)
// При удержании кнопки первые 500 мс ничего не происходит
#define REPEAT_DELAY_MS     500

// Интервал между автоповторами (мс)
// После начала повтора каждые 100 мс кнопка срабатывает заново
#define REPEAT_INTERVAL_MS  100

// Интервал мигания редактируемого разряда (мс)
// Моргает каждые 500 мс (0.5 сек вкл / 0.5 сек выкл)
#define BLINK_INTERVAL_MS   500

// Задержка антидребезга (мс)
// Изменение состояния кнопки фиксируется только если оно стабильно в течение 30 мс
#define DEBOUNCE_MS         30

typedef enum {
    MAIN_MENU_SET_TIME,
    MAIN_MENU_SET_DUTY,
    MAIN_MENU_RESET,
    MAIN_MENU_COUNT
} MainMenuItem;

typedef struct {
    // Состояние
    SystemState state;
    MainMenuItem selectedMenuItem;
    
    // Для SET_TIME
    time_t originalTime;
    time_t editTime;
    uint8_t editStep;
    bool blinkState;
    uint32_t lastBlinkTime;
    
    // Для SET_DUTY
    uint8_t originalDuty;
    uint8_t editDuty;
    
    // Для кнопок
    bool buttonPrevState[BUTTON_COUNT];
    uint32_t buttonPressTime[BUTTON_COUNT];
    bool longPressSent[BUTTON_COUNT];
    bool repeatActive[BUTTON_COUNT];
    uint32_t lastRepeatTime[BUTTON_COUNT];
    uint32_t lastDebounceTime[BUTTON_COUNT];
    bool buttonStableState[BUTTON_COUNT];
    
} MenuContext;

MenuContext menu;

// ==================== Отображение ====================
static void FormatTime(char* buf, const time_t* t) {
    buf[0] = '0' + t->hour / 10;
    buf[1] = '0' + t->hour % 10;
    buf[2] = '0' + t->min / 10;
    buf[3] = '0' + t->min % 10;
    buf[4] = '0' + t->sec / 10;
    buf[5] = '0' + t->sec % 10;
}

static void UpdateDisplay(void) {
    switch (menu.state) {
        case STATE_CLOCK: {
            time_t now = ClockManager_GetTime(1);
            char buf[7];
            FormatTime(buf, &now);
            Segment_SetString(buf);
            break;
        }
        
        case STATE_MAIN_MENU: {
            switch (menu.selectedMenuItem) {
                case MAIN_MENU_SET_TIME:
                    Segment_SetString("SET T ");
                    break;
                case MAIN_MENU_SET_DUTY:
                    Segment_SetString("SET D ");
                    break;
                case MAIN_MENU_RESET:
                    Segment_SetString("RESET ");
                    break;
                default:
                    break;
            }
            break;
        }
        
        case STATE_SET_TIME: {
            char buf[7];
            FormatTime(buf, &menu.editTime);
            if (menu.blinkState && menu.editStep < 6) {
                buf[menu.editStep] = ' ';
            }
            Segment_SetString(buf);
            break;
        }
        
        case STATE_SET_DUTY: {
            char buf[6] = {'D', 'U', 'T', 'Y', ' ' , ' '};
            if (menu.editDuty == 10) {
                buf[4] = '1';
                buf[5] = '0';
            } else {
                buf[5] = '0' + menu.editDuty;
            }
            Segment_SetString(buf);
            break;
        }
        
        case STATE_RESET_CONFIRM:
            Segment_SetString("RESET ");
            break;
    }
}

// ==================== Логика SET_TIME ====================
static void IncreaseTimeDigit(void) {
    uint8_t tens, units;
    switch (menu.editStep) {
        case 0: // десятки часов (0-2)
            tens = menu.editTime.hour / 10;
            units = menu.editTime.hour % 10;
            tens++;
            if (tens > 2) tens = 0;
            menu.editTime.hour = tens * 10 + units;
            break;
            
        case 1: // единицы часов (0-9, но с учетом десятков)
            tens = menu.editTime.hour / 10;
            units = menu.editTime.hour % 10;
            units++;
            if (tens == 2 && units > 3) units = 0;  // 23 → 20
            if (units > 9) units = 0;
            menu.editTime.hour = tens * 10 + units;
            break;
            
        case 2: // десятки минут (0-5)
            tens = menu.editTime.min / 10;
            units = menu.editTime.min % 10;
            tens = (tens + 1) % 6;
            menu.editTime.min = tens * 10 + units;
            break;
            
        case 3: // единицы минут (0-9)
            units = (menu.editTime.min % 10 + 1) % 10;
            menu.editTime.min = (menu.editTime.min / 10) * 10 + units;
            break;
            
        case 4: // десятки секунд (0-5)
            tens = menu.editTime.sec / 10;
            units = menu.editTime.sec % 10;
            tens = (tens + 1) % 6;
            menu.editTime.sec = tens * 10 + units;
            break;
            
        case 5: // единицы секунд (0-9)
            units = (menu.editTime.sec % 10 + 1) % 10;
            menu.editTime.sec = (menu.editTime.sec / 10) * 10 + units;
            break;
    }
    UpdateDisplay();
}

static void DecreaseTimeDigit(void) {
    uint8_t tens, units;
    switch (menu.editStep) {
        case 0: // десятки часов (0-2)
            tens = menu.editTime.hour / 10;
            units = menu.editTime.hour % 10;
            if (tens == 0) tens = 2;
            else tens--;
            menu.editTime.hour = tens * 10 + units;
            break;
            
        case 1: // единицы часов
            tens = menu.editTime.hour / 10;
            units = menu.editTime.hour % 10;
            if (units == 0) {
                units = (tens == 2) ? 3 : 9;
            } else {
                units--;
            }
            menu.editTime.hour = tens * 10 + units;
            break;
            
        case 2: // десятки минут (0-5)
            tens = menu.editTime.min / 10;
            units = menu.editTime.min % 10;
            tens = (tens == 0) ? 5 : tens - 1;
            menu.editTime.min = tens * 10 + units;
            break;
            
        case 3: // единицы минут
            units = (menu.editTime.min % 10 == 0) ? 9 : (menu.editTime.min % 10) - 1;
            menu.editTime.min = (menu.editTime.min / 10) * 10 + units;
            break;
            
        case 4: // десятки секунд (0-5)
            tens = menu.editTime.sec / 10;
            units = menu.editTime.sec % 10;
            tens = (tens == 0) ? 5 : tens - 1;
            menu.editTime.sec = tens * 10 + units;
            break;
            
        case 5: // единицы секунд
            units = (menu.editTime.sec % 10 == 0) ? 9 : (menu.editTime.sec % 10) - 1;
            menu.editTime.sec = (menu.editTime.sec / 10) * 10 + units;
            break;
    }
    UpdateDisplay();
}

// ==================== Обработка кнопок ====================
static void ProcessButton(Button_Type btn, bool longPress) {
    // Длинное нажатие SELECT в режиме часов - вход в меню
    if (menu.state == STATE_CLOCK && longPress && btn == BUTTON_SELECT) {
        menu.state = STATE_MAIN_MENU;
        menu.selectedMenuItem = MAIN_MENU_SET_TIME;
        UpdateDisplay();
        return;
    }
    
    switch (menu.state) {
        case STATE_MAIN_MENU:
            if (btn == BUTTON_UP) {
                menu.selectedMenuItem++;
                if (menu.selectedMenuItem >= MAIN_MENU_COUNT) {
                    menu.selectedMenuItem = 0;
                }
                UpdateDisplay();
            }
            else if (btn == BUTTON_DOWN) {
                if (menu.selectedMenuItem == 0) {
                    menu.selectedMenuItem = MAIN_MENU_COUNT - 1;
                } else {
                    menu.selectedMenuItem--;
                }
                UpdateDisplay();
            }
            else if (btn == BUTTON_SELECT && !longPress) {
                switch (menu.selectedMenuItem) {
                    case MAIN_MENU_SET_TIME:
                        menu.state = STATE_SET_TIME;
                        menu.originalTime = ClockManager_GetTime(0);
                        menu.editTime = menu.originalTime;
                        menu.editStep = 0;
                        menu.blinkState = true;
                        menu.lastBlinkTime = HAL_GetTick();
                        break;
                    case MAIN_MENU_SET_DUTY:
                        menu.state = STATE_SET_DUTY;
                        menu.originalDuty = ClockManager_GetDuty();
                        menu.editDuty = menu.originalDuty;
                        break;
                    case MAIN_MENU_RESET:
                        menu.state = STATE_RESET_CONFIRM;
                        break;
                    default: break;
                }
                UpdateDisplay();
            }
            else if (btn == BUTTON_BACK) {
                menu.state = STATE_CLOCK;
                UpdateDisplay();
            }
            break;
            
        case STATE_SET_TIME:
            if (btn == BUTTON_UP) {
                IncreaseTimeDigit();
            }
            else if (btn == BUTTON_DOWN) {
                DecreaseTimeDigit();
            }
            else if (btn == BUTTON_SELECT) {
                menu.editStep++;
                if (menu.editStep >= 6) {
                    ClockManager_SetTime(menu.editTime.hour, menu.editTime.min, menu.editTime.sec);
                    menu.state = STATE_CLOCK;
                }
                UpdateDisplay();
            }
            else if (btn == BUTTON_BACK) {
                menu.state = STATE_CLOCK;
                UpdateDisplay();
            }
            break;
            
        case STATE_SET_DUTY:
            if (btn == BUTTON_UP && menu.editDuty < 10) {
                menu.editDuty++;
                Segment_SetBrightness(menu.editDuty * 10);
                UpdateDisplay();
            }
            else if (btn == BUTTON_DOWN && menu.editDuty > 0) {
                menu.editDuty--;
                Segment_SetBrightness(menu.editDuty * 10);
                UpdateDisplay();
            }
            else if (btn == BUTTON_SELECT) {
                ClockManager_SetDuty(menu.editDuty);
                menu.state = STATE_CLOCK;
                UpdateDisplay();
            }
            else if (btn == BUTTON_BACK) {
                menu.state = STATE_CLOCK;
                Segment_SetBrightness(menu.originalDuty * 10);
                UpdateDisplay();
            }
            break;
            
        case STATE_RESET_CONFIRM:
            if (btn == BUTTON_SELECT) {
                ClockManager_ResetTime();
                ClockManager_SetDuty(8);
                menu.state = STATE_CLOCK;
                UpdateDisplay();
            }
            else if (btn == BUTTON_BACK) {
                menu.state = STATE_CLOCK;
                UpdateDisplay();
            }
            break;
            
        default:
            break;
    }
}

// ==================== Публичные функции ====================
void Menu_Init(void) {
    menu.state = STATE_CLOCK;
    menu.selectedMenuItem = MAIN_MENU_SET_TIME;
    menu.editStep = 0;
    menu.blinkState = false;
    menu.lastBlinkTime = 0;
    
    for (int i = 0; i < BUTTON_COUNT; i++) {
        menu.buttonPrevState[i] = false;
        menu.buttonPressTime[i] = 0;
        menu.longPressSent[i] = false;
        menu.repeatActive[i] = false;
        menu.lastDebounceTime[i] = 0;
        menu.buttonStableState[i] = false;
    }
}

void Menu_Process(void) {
    uint32_t tick = HAL_GetTick();
    
    if (menu.state == STATE_SET_TIME) {
        if (tick - menu.lastBlinkTime >= BLINK_INTERVAL_MS) {
            menu.lastBlinkTime = tick;
            menu.blinkState = !menu.blinkState;
            UpdateDisplay();
        }
    }
    
    for (int i = 0; i < BUTTON_COUNT; i++) {
        bool rawPressed = ReadButton(i);
        bool pressed;

        // Антидребезг
        if (rawPressed != menu.buttonStableState[i]) {
            menu.lastDebounceTime[i] = tick;
            menu.buttonStableState[i] = rawPressed;
        }

        if ((tick - menu.lastDebounceTime[i]) >= DEBOUNCE_MS) {
            pressed = menu.buttonStableState[i];
        } else {
            pressed = menu.buttonPrevState[i]; // старое значение пока не стабилизировалось
        }
        bool wasPressed = menu.buttonPrevState[i];
        
        if (pressed && !wasPressed) {
            menu.buttonPressTime[i] = tick;
            menu.longPressSent[i] = false;
            menu.repeatActive[i] = false;
        }
        else if (pressed && wasPressed) {
            if (!menu.longPressSent[i] && (tick - menu.buttonPressTime[i] >= LONG_PRESS_MS)) {
                menu.longPressSent[i] = true;
                ProcessButton((Button_Type)i, true);
            }
            else if (menu.longPressSent[i] && !menu.repeatActive[i] && 
                     (tick - menu.buttonPressTime[i] >= REPEAT_DELAY_MS)) {
                menu.repeatActive[i] = true;
                menu.lastRepeatTime[i] = tick;
                ProcessButton((Button_Type)i, true);
            }
            else if (menu.repeatActive[i] && (tick - menu.lastRepeatTime[i] >= REPEAT_INTERVAL_MS)) {
                menu.lastRepeatTime[i] = tick;
                ProcessButton((Button_Type)i, true);
            }
        }
        else if (!pressed && wasPressed) {
            if (!menu.longPressSent[i]) {
                ProcessButton((Button_Type)i, false);
            }
            menu.repeatActive[i] = false;
        }
        
        menu.buttonPrevState[i] = pressed;
    }
    
    static uint32_t lastClockUpdate = 0;
    if (menu.state == STATE_CLOCK && (tick - lastClockUpdate >= 200)) {
        lastClockUpdate = tick;
        UpdateDisplay();
    }
}

SystemState Menu_GetState(void) {
    return menu.state;
}