#pragma once

#include "IrTxGateTypes.h"
#include <cstddef>
#include <cstdint>

#if defined(__GNUC__)
#define IR_TX_BSRR_WAVE_HOT __attribute__((always_inline)) inline
#else
#define IR_TX_BSRR_WAVE_HOT inline
#endif

/**
 * Генерация потока 32-бит слов для GPIO BSRR из RLE-сегментов IrTxGateRun.
 * За один период несущей — multiply физических тиков; при gate — powerN из них HIGH (N ≤ multiply/2).
 */
class IrTxBsrrWave {
public:
    void configure(uint32_t setW, uint32_t resetW, IrTxGateRun* r, size_t n, uint16_t multiply, uint16_t powerN) {
        setWord = setW;
        resetWord = resetW;
        runs = r;
        runCount = n;
        multiply_ = multiply < 2 ? 2 : multiply;
        const uint16_t cap = static_cast<uint16_t>(multiply_ / 2U);
        powerN_ = (powerN > cap) ? cap : powerN;
        resetWave();
    }

    void resetWave() {
        runIndex_ = 0;
        slotInPeriod_ = 0;
        ticksLeftInRun_ = 0;
        if (runCount > 0U && runs != nullptr) {
            ticksLeftInRun_ = runs[0].lenTicks;
        }
    }

    IR_TX_BSRR_WAVE_HOT uint32_t nextWord() {
        if (runIndex_ >= runCount) {
            return resetWord;
        }
        const bool gate = runs[runIndex_].gate;
        uint32_t out;
        if (!gate) {
            slotInPeriod_ = 0;
            out = resetWord;
        } else {
            out = (slotInPeriod_ < powerN_) ? setWord : resetWord;
            slotInPeriod_++;
            if (slotInPeriod_ >= multiply_) {
                slotInPeriod_ = 0;
            }
        }

        if (ticksLeftInRun_ > 0) {
            ticksLeftInRun_--;
        }
        if (ticksLeftInRun_ == 0) {
            runIndex_++;
            if (runIndex_ < runCount) {
                ticksLeftInRun_ = runs[runIndex_].lenTicks;
            }
        }
        return out;
    }

    IR_TX_BSRR_WAVE_HOT void fill(uint32_t* dst, uint16_t count) {
        if (dst == nullptr || count == 0) {
            return;
        }
        do {
            *dst++ = nextWord();
        } while (--count != 0);
    }

private:
    uint32_t setWord = 0;
    uint32_t resetWord = 0;
    IrTxGateRun* runs = nullptr;
    size_t runCount = 0;
    uint16_t multiply_ = 2;
    uint16_t powerN_ = 1;
    size_t runIndex_ = 0;
    uint16_t ticksLeftInRun_ = 0;
    uint16_t slotInPeriod_ = 0;
};
