// SPDX-FileComment: This file is part of TNL - Template Numerical Library (https://tnl-project.org/)
// SPDX-License-Identifier: MIT

#pragma once

#include "CSRAdaptiveKernelView.h"
#include "isSegmentReductionKernel.h"

#include "../Segments/detail/FetchLambdaAdapter.h"
#include "isSegmentsReductionKernel.h"

namespace TNL::Algorithms::SegmentsReductionKernels {

template< typename Index, typename Device >
struct CSRAdaptiveKernel
{
   using IndexType = Index;
   using DeviceType = Device;
   using ViewType = CSRAdaptiveKernelView< Index, Device >;
   using ConstViewType = CSRAdaptiveKernelView< Index, Device >;
   using BlocksType = typename ViewType::BlocksType;
   using BlocksView = typename BlocksType::ViewType;

   [[nodiscard]] static constexpr int
   MaxValueSizeLog()
   {
      return ViewType::MaxValueSizeLog;
   }

   [[nodiscard]] static int
   getSizeValueLog( const int& i )
   {
      return Segments::detail::CSRAdaptiveKernelParameters<>::getSizeValueLog( i );
   }

   [[nodiscard]] static std::string
   getKernelType();

   template< typename Segments >
   void
   init( const Segments& segments );

   void
   reset();

   [[nodiscard]] __cuda_callable__
   ViewType
   getView();

   [[nodiscard]] __cuda_callable__
   ConstViewType
   getConstView() const;

   template<
      typename SegmentsView,
      typename Fetch,
      typename Reduction,
      typename ResultKeeper,
      typename Value = typename Segments::detail::FetchLambdaAdapter< Index, Fetch >::ReturnType >
   [[deprecated( "Use TNL::Algorithms::Segments::reduceSegments instead" )]] void
   reduceSegments(
      const SegmentsView& segments,
      Index begin,
      Index end,
      Fetch& fetch,
      const Reduction& reduction,
      ResultKeeper& keeper,
      const Value& identity = Reduction::template getIdentity< Value >() ) const;

   template<
      typename SegmentsView,
      typename Fetch,
      typename Reduction,
      typename ResultKeeper,
      typename Value = typename Segments::detail::FetchLambdaAdapter< Index, Fetch >::ReturnType >
   [[deprecated( "Use TNL::Algorithms::Segments::reduceAllSegments instead" )]] void
   reduceAllSegments(
      const SegmentsView& segments,
      Fetch& fetch,
      const Reduction& reduction,
      ResultKeeper& keeper,
      const Value& identity = Reduction::template getIdentity< Value >() ) const;

protected:
   template< int SizeOfValue, typename Offsets >
   Index
   findLimit( Index start, const Offsets& offsets, Index size, Segments::detail::Type& type );

   template< int SizeOfValue, typename Offsets >
   void
   initValueSize( const Offsets& offsets );

   /**
    * \brief  blocksArray[ i ] stores blocks for sizeof( Value ) == 2^i.
    */
   BlocksType blocksArray[ MaxValueSizeLog() ];

   ViewType view;
};

template< typename Index, typename Device >
struct isSegmentsReductionKernel< CSRAdaptiveKernel< Index, Device > > : std::true_type
{};

}  // namespace TNL::Algorithms::SegmentsReductionKernels

#include "CSRAdaptiveKernel.hpp"
