/// @file fl/delay.cpp
/// Implementation for delay utilities

// Define this before including headers to prevent duplicate specializations in delay_cycles_generic.h
#define FL_DELAY_CPP_SPECIALIZATIONS

#include "fl/stl/stdint.h"
#include "fl/system/delay.h"
#include "platforms/cycle_type.h"
#include "fl/stl/compiler_control.h"
#include "fl/system/sketch_macros.h"
#include "fl/stl/chrono.h"

// ============================================================================
// Platform-specific includes
// ============================================================================

#include "platforms/delay.h"
#include "platforms/time_platform.h"
#include "platforms/coroutine_runtime.h"

#if SKETCH_HAS_LARGE_MEMORY
#include "fl/task/executor.h"
#endif

// Include stub time header for delay override check (only on stub platform)
#if defined(FASTLED_STUB_IMPL) && (!defined(ARDUINO) || defined(FASTLED_USE_STUB_ARDUINO))
// IWYU pragma: begin_keep
#include "platforms/stub/time_stub.h"  // ok platform headers
// IWYU pragma: end_keep  // ok platform headers (stub-specific delay override check)
#endif

namespace fl {

// ============================================================================
// Internal platform-specific delay helpers
// ============================================================================
// (Moved to fl::platforms::delay() - no longer needed here)

// ============================================================================
// Runtime delayNanoseconds implementations
// ============================================================================

void delayNanoseconds(fl::u32 ns) FL_NOEXCEPT {
  delayNanoseconds_impl(ns);
}

void delayNanoseconds(fl::u32 ns, fl::u32 hz) FL_NOEXCEPT {
  delayNanoseconds_impl(ns, hz);
}

// ============================================================================
// delaycycles template specializations
// ============================================================================
// These pre-instantiated specializations optimize compilation time and code size
// for common cycle counts.

// Specializations for small negative and zero cycles
template<> FASTLED_FORCE_INLINE void delaycycles<-10>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-9>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-8>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-7>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-6>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-5>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-4>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-3>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-2>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<-1>() FL_NOEXCEPT {}
template<> FASTLED_FORCE_INLINE void delaycycles<0>() FL_NOEXCEPT {}

// Specializations for small positive cycles
// Note: These MUST NOT use FASTLED_FORCE_INLINE because with LTO enabled,
// inline functions don't generate external symbols that the linker can resolve.
// Using just inline or no storage class allows the linker to find these.
template<> void delaycycles<1>() FL_NOEXCEPT { FL_NOP; }
template<> void delaycycles<2>() FL_NOEXCEPT { FL_NOP2; }
template<> void delaycycles<3>() FL_NOEXCEPT {
  FL_NOP;
  FL_NOP2;
}
template<> void delaycycles<4>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
}
template<> void delaycycles<5>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
  FL_NOP;
}

template<> void delaycycles<6>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
}
template<> void delaycycles<7>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
  FL_NOP;
}
template<> void delaycycles<8>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
}
template<> void delaycycles<9>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
  FL_NOP;
}
template<> void delaycycles<10>() FL_NOEXCEPT {
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
  FL_NOP2;
}

// Larger cycle counts (9-50) to ensure linker can resolve symbols
// These are commonly generated by template instantiation
template<> void delaycycles<11>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<1>(); }
template<> void delaycycles<12>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<2>(); }
template<> void delaycycles<13>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<3>(); }
template<> void delaycycles<14>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<4>(); }
template<> void delaycycles<15>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<5>(); }
template<> void delaycycles<16>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<6>(); }
template<> void delaycycles<17>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<7>(); }
template<> void delaycycles<18>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<8>(); }
template<> void delaycycles<19>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<9>(); }
template<> void delaycycles<20>() FL_NOEXCEPT { delaycycles<10>(); delaycycles<10>(); }
template<> void delaycycles<21>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<1>(); }
template<> void delaycycles<22>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<2>(); }
template<> void delaycycles<23>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<3>(); }
template<> void delaycycles<24>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<4>(); }
template<> void delaycycles<25>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<5>(); }
template<> void delaycycles<26>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<6>(); }
template<> void delaycycles<27>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<7>(); }
template<> void delaycycles<28>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<8>(); }
template<> void delaycycles<29>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<9>(); }
template<> void delaycycles<30>() FL_NOEXCEPT { delaycycles<20>(); delaycycles<10>(); }
template<> void delaycycles<31>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<1>(); }
template<> void delaycycles<32>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<2>(); }
template<> void delaycycles<33>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<3>(); }
template<> void delaycycles<34>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<4>(); }
template<> void delaycycles<35>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<5>(); }
template<> void delaycycles<36>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<6>(); }
template<> void delaycycles<37>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<7>(); }
template<> void delaycycles<38>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<8>(); }
template<> void delaycycles<39>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<9>(); }
template<> void delaycycles<40>() FL_NOEXCEPT { delaycycles<30>(); delaycycles<10>(); }
template<> void delaycycles<41>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<1>(); }
template<> void delaycycles<42>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<2>(); }
template<> void delaycycles<43>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<3>(); }
template<> void delaycycles<44>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<4>(); }
template<> void delaycycles<45>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<5>(); }
template<> void delaycycles<46>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<6>(); }
template<> void delaycycles<47>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<7>(); }
template<> void delaycycles<48>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<8>(); }
template<> void delaycycles<49>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<9>(); }
template<> void delaycycles<50>() FL_NOEXCEPT { delaycycles<40>(); delaycycles<10>(); }

// SPI timing optimizations removed: binary splitting now handles these efficiently
// delaycycles<14>() → splits to delaycycles<7>() + delaycycles<7>()
// delaycycles<23>() → splits to delaycycles<11>() + delaycycles<12>()
// delaycycles<37>() → splits to delaycycles<18>() + delaycycles<19>()

// ============================================================================
// Millisecond and Microsecond delay implementations
// ============================================================================

namespace detail {

void delay_impl(u32 ms, bool run_async) FL_NOEXCEPT {
#if SKETCH_HAS_LARGE_MEMORY
  // Check if delay override is active (for fast testing with stub platform)
  // When override is active, skip async pumping and use platform delay directly
#if defined(FASTLED_STUB_IMPL) && (!defined(ARDUINO) || defined(FASTLED_USE_STUB_ARDUINO))
  if (isDelayOverrideActive()) {
    fl::platforms::delay(ms);  // Use platform override directly
    return;
  }
#endif

  if (run_async && ms > 0) {
    task::run(ms * 1000);
  } else {
    fl::platforms::delay(ms);  // Use platform layer for raw delay
  }
#else
  (void)run_async;  // Suppress unused parameter warning
  fl::platforms::delay(ms);  // Use platform layer for raw delay
#endif
}

}  // namespace detail

void delayMillis(u32 ms) FL_NOEXCEPT {
  // Legacy function - no async pumping (backward compatibility)
  detail::delay_impl(ms, false);
}

void delayMicroseconds(u32 us) FL_NOEXCEPT {
  // Direct pass-through to platform layer (no async pumping for microsecond precision)
  fl::platforms::delayMicroseconds(us);
}



}  // namespace fl
