#pragma once
#include "IR_DecoderRaw.h"
#include "PacketTypes.h"
#include "IR_Encoder.h"

class IR_Decoder : public IR_DecoderRaw
{
private:
    // static std::list<IR_Decoder *> dec_list;
    static std::list<IR_Decoder*>& get_dec_list();
    void _tick();

    uint32_t acceptSendTimer;
    bool isWaitingAcceptSend;
    uint16_t addrAcceptSendTo;

    uint16_t acceptDelay = IR_ResponseDelay;
    uint8_t acceptCustomByte;

    bool extiEnabled_ = false;
    bool rxExtiPreemptConfigured_ = false;
    uint32_t rxExtiPreemptValue_ = 0;

public:
    PacketTypes::Data gotData;
    PacketTypes::DataBack gotBackData;
    PacketTypes::Accept gotAccept;
    PacketTypes::Request gotRequest;
    PacketTypes::BasePack gotRaw;

    // IR_Decoder();
    /** @param enableOnConstruct true — вызвать enable() из конструктора; false — отложенный enable() (NVIC и т.д.), tick — tickThis() / tick(). */
    IR_Decoder(const uint8_t pin, uint16_t addr = 0, IR_Encoder *encPair = nullptr, bool enableOnConstruct = true);

    std::function<void()> operator()();

    /**
     * Arduino STM32: после attachInterrupt ядро выставляет свой приоритет EXTI.
     * Если вызывали setReceiveExtiPreemptPriority(), здесь он применяется поверх (обычно нужен выше срочности, чем DMA ИК-TX).
     * На других платформах поведение без изменений.
     */
    void enable();
    void disable();

#if defined(ARDUINO_ARCH_STM32) && !defined(HAL_EXTI_MODULE_DISABLED)
    /**
     * Задать preempt-приоритет NVIC для EXTI линии этого пина (тот же смысл, что второй аргумент CMSIS NVIC_SetPriority).
     * Вызывайте до или после enable(); при активном приёме применяется сразу.
     * При использовании DMA на передачу ИК preempt приёма должен быть меньше, чем у DMA TX (выше срочность прерывания).
     */
    void setReceiveExtiPreemptPriority(uint32_t preempt);
#endif
    
    bool isReceive(uint8_t type);

    ~IR_Decoder();

    /** Обойти все экземпляры из внутреннего списка и вызвать tick у каждого. */
    static void tick();

    /** Tick только этого декодера (без обхода списка). Не комбинируйте с static tick() для того же экземпляра. */
    void tickThis() { _tick(); }

    inline void setAcceptDelay(uint16_t acceptDelay)
    {
        this->acceptDelay = acceptDelay;
    }
    inline uint16_t getAcceptDelay()
    {
        return this->acceptDelay;
    }
};
