#pragma once

// IWYU pragma: private

/// @file bus_traits.h
/// @brief BusTraits<Bus::LCD_SPI> + BusTraits<Bus::LCD_CLOCKLESS> for ESP32-S3.
///
/// Both buses share the LCD_CAM I80 peripheral on ESP32-S3 — LCD_SPI drives
/// true SPI chipsets (APA102 etc.) and LCD_CLOCKLESS drives clockless chipsets
/// (WS2812 etc.). They live in the same header because they share the same
/// `FASTLED_ESP32_HAS_LCD_SPI` feature flag and platform.

#include "fl/stl/compiler_control.h"
#include "platforms/is_platform.h"

#if defined(FL_IS_ESP32)
#include "platforms/esp/32/feature_flags/enabled.h"
#endif

#if defined(FL_IS_ESP32) && FASTLED_ESP32_HAS_LCD_SPI

#include "fl/channels/bus.h"
#include "fl/channels/bus_priorities.h"
#include "fl/channels/bus_traits.h"
#include "fl/channels/config.h"
#include "fl/channels/driver.h"
#include "fl/channels/manager.h"
#include "fl/stl/shared_ptr.h"
#include "fl/stl/type_traits.h"
#include "platforms/esp/32/drivers/lcd_spi/channel_driver_lcd_clockless.h"
#include "platforms/esp/32/drivers/lcd_spi/channel_driver_lcd_spi.h"

namespace fl {

// createLcdSpiEngine() and createLcdClocklessEngine() are declared in the
// driver headers included above.

template<> struct BusTraits<Bus::LCD_SPI> {
    using Driver = IChannelDriver;

    static fl::shared_ptr<Driver> instancePtr() FL_NOEXCEPT {
        static fl::shared_ptr<Driver> gHolder = createLcdSpiEngine();
        return gHolder;
    }

    static Driver& instance() FL_NOEXCEPT { return *instancePtr(); }

    static void registerWithManager() FL_NOEXCEPT {
        ChannelManager::instance().addDriver(default_bus_priority(Bus::LCD_SPI), instancePtr());
    }
};

template<> struct BusSupports<Bus::LCD_SPI, SpiChipsetConfig> : fl::true_type {};

template<> struct BusTraits<Bus::LCD_CLOCKLESS> {
    using Driver = IChannelDriver;

    static fl::shared_ptr<Driver> instancePtr() FL_NOEXCEPT {
        static fl::shared_ptr<Driver> gHolder = createLcdClocklessEngine();
        return gHolder;
    }

    static Driver& instance() FL_NOEXCEPT { return *instancePtr(); }

    static void registerWithManager() FL_NOEXCEPT {
        ChannelManager::instance().addDriver(default_bus_priority(Bus::LCD_CLOCKLESS), instancePtr());
    }
};

template<> struct BusSupports<Bus::LCD_CLOCKLESS, ClocklessChipset> : fl::true_type {};

}  // namespace fl

#endif  // FL_IS_ESP32 && FASTLED_ESP32_HAS_LCD_SPI
