/**
 * @file main.c
 * @brief Bike rear light implementation for ATTINY202 with low-power standby.
 */

#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>

#define BUTTON_PIN_MASK 0x01 // PA0
#define PA1_SET_MASK 0x02    // LED 1–2
#define PA2_SET_MASK 0x04    // LED 3–6
#define PA3_SET_MASK 0x08    // LED 7–8
#define PA6_SET_MASK 0x40    // Green LED
#define PA7_SET_MASK 0x80    // Red LED

#define MAIN_LOOP_SLEEP 50U                 // Loop period in ms
#define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold
#define BUTTON_IGNORE_DURATION_MS 1000U     // Ignore after long press

#define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP)

volatile bool bLedEnabled = false;
volatile bool bBtnPressed = false;

static inline void leds_off(void);
static inline void leds_on(void);
static void battery_level_indicator(void);
static void handleSwitch(void);
void blinkLed(bool resetCounters);

/* --- Timer init: Use RTC PIT for periodic wake-up --- */
void init_timer(void)
{
    RTC.CLKSEL = RTC_CLKSEL_INT1K_gc; // 1 kHz ULP clock for RTC
    while (RTC.STATUS > 0)
    {
    } // Wait for sync

    RTC.PITINTCTRL = RTC_PI_bm;        // Enable PIT interrupt
    RTC.PITCTRLA = RTC_PERIOD_CYC64_gc // ≈64 ms wake-up (~50 ms)
                   | RTC_PITEN_bm;     // Enable PIT
}

ISR(RTC_PIT_vect)
{
    RTC.PITINTFLAGS = RTC_PI_bm; // Clear interrupt flag
}

/* --- MAIN --- */
int main(void)
{
    // Configure LED pins as outputs
    VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK | PA6_SET_MASK | PA7_SET_MASK);

    // Configure PA0 as input with pull-up
    VPORTA.DIR &= ~BUTTON_PIN_MASK;    // Input
    PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // Pull-up enabled

    // Ensure all LEDs off at startup
    leds_off();
    battery_level_indicator(); // TODO: Implement

    bool bLedEnabledOld = bLedEnabled;

    cli();
    init_timer();
    sei();

    set_sleep_mode(SLEEP_MODE_STANDBY);

    while (1)
    {
        handleSwitch(); // Check switch state

        // Light LEDs while button is pressed
        if (bBtnPressed)
        {
            leds_on();
        }
        else
        {
            leds_off();
        }

        // Long press detected → show confirmation blink
        if (bLedEnabledOld != bLedEnabled)
        {
            bLedEnabledOld = bLedEnabled;

            leds_off();
            _delay_ms(BUTTON_IGNORE_DURATION_MS / 10);
            leds_on();
            _delay_ms(BUTTON_IGNORE_DURATION_MS / 10);
            leds_off();
            _delay_ms(BUTTON_IGNORE_DURATION_MS);

            blinkLed(true); // reset blink state machine
        }
        else
        {
            if (bLedEnabled && !bBtnPressed)
            {
                blinkLed(false); // run normal blink
            }
        }

        sleep_enable();
        sleep_cpu(); // Sleep until PIT wakes
        sleep_disable();
    }
}

/**
 * @brief Turn off all controlled LEDs (PA1, PA2, PA3)
 */
static inline void leds_off(void)
{
    VPORTA.OUT &= (uint8_t) ~(PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK);
}

/**
 * @brief Turn on all controlled LEDs (PA1, PA2, PA3)
 */
static inline void leds_on(void)
{
    VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK);
}

/**
 * @brief Battery monitoring
 */
static void battery_level_indicator(void)
{
    // TODO: Implement
    VPORTA.OUT |= (PA6_SET_MASK | PA7_SET_MASK); // green + red OFF
}

/**
 * @brief Handle momentary switch input on PA0
 *
 * A long press toggles ::bLedEnabled.
 */
static void handleSwitch(void)
{
    static uint16_t pressTicks = 0;  ///< Press duration counter
    static bool prevPressed = false; ///< Previous button state

    bool pressed = !(VPORTA.IN & BUTTON_PIN_MASK); // Active-low

    if (pressed)
    {
        bBtnPressed = true;
        if (pressTicks < 0xFFFF)
            pressTicks++; // Prevent overflow
    }
    else
    {
        bBtnPressed = false;
        pressTicks = 0;
    }

    if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS))
    {
        bLedEnabled = !bLedEnabled; // Toggle LED blinking
    }

    prevPressed = pressed;
}

/**
 * @brief LED blink state machine (bike rear light style)
 *
 * Normal cycle:
 *   0: all off, wait 250 ms
 *   2: LED 1–2 + 7–8 ON, wait 50 ms
 *   5: all off, wait 100 ms
 *   7: LED 1–2 + 7–8 ON, wait 50 ms
 *   10: all off, wait 250 ms
 *   12: LED 3–6 ON, wait 50 ms
 *   14: all off, wait 100 ms
 *   16: LED 3–6 ON, wait 50 ms
 *   18: all off, wait 250 ms → restart
 * Special: every 3rd cycle, all LEDs ON for 250 ms
 */
void blinkLed(bool resetCounters)
{
    const uint8_t T50 = MS_TO_TICKS(50);
    const uint8_t T100 = MS_TO_TICKS(100);
    const uint8_t T250 = MS_TO_TICKS(250);

    static uint16_t counter = 0;
    static uint8_t state = 2; // start with LEDs-on state
    static uint8_t cycle = 0;

    if (resetCounters)
    {
        counter = 0;
        state = 12; // start with LEDs on
        cycle = 0;
    }

    counter++;

    switch (state)
    {
    case 0: // all LEDs off, wait 250 ms
        leds_off();
        if (counter >= T250)
        {
            counter = 0;
            state = 2;
        }
        break;

    case 2: // LED 1–2 + 7–8 on, wait 50 ms
        VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK);
        if (counter >= T50)
        {
            counter = 0;
            state = 5;
        }
        break;

    case 5: // all LEDs off, wait 100 ms
        leds_off();
        if (counter >= T100)
        {
            counter = 0;
            state = 7;
        }
        break;

    case 7: // LED 1–2 + 7–8 on, wait 50 ms
        VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK);
        if (counter >= T50)
        {
            counter = 0;
            state = 10;
        }
        break;

    case 10: // all LEDs off, wait 250 ms
        leds_off();
        if (counter >= T250)
        {
            counter = 0;
            state = 12;
        }
        break;

    case 12: // LED 3–6 on, wait 50 ms
        VPORTA.OUT |= PA2_SET_MASK;
        if (counter >= T50)
        {
            counter = 0;
            state = 14;
        }
        break;

    case 14: // all LEDs off, wait 100 ms
        leds_off();
        if (counter >= T100)
        {
            counter = 0;
            state = 16;
        }
        break;

    case 16: // LED 3–6 on, wait 50 ms
        VPORTA.OUT |= PA2_SET_MASK;
        if (counter >= T50)
        {
            counter = 0;
            state = 18;
        }
        break;

    case 18: // all LEDs off, wait 250 ms
        leds_off();
        if (counter >= T250)
        {
            counter = 0;
            if (++cycle >= 3)
            {
                cycle = 0;
                state = 20; // special all-LEDs-on state
            }
            else
            {
                state = 0; // restart normal cycle
            }
        }
        break;

    case 20: // special: all LEDs on for 250 ms
        VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK);
        if (counter >= T250)
        {
            counter = 0;
            state = 0;
        }
        break;
    }
}
