// Copyright (C) 2026  EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#pragma once
#include <memory>
#include "StOpt/regression/BaseRegression.h"
#include "StOpt/regression/GlobalRegression.h"
#include "StOpt/regression/LocalConstRegression.h"
#include "StOpt/regression/LocalLinearRegression.h"
#include "StOpt/core/grids/InterpolatorSpectral.h"
#include "StOpt/core/utils/Polynomials1D.h"

/// \brief  Using dynamic_cast can mimick the behavior of heritage

namespace StOpt {

template<typename T>
T dispatchRegressionGetValue(const BaseRegression& p_reg,
                                     const Eigen::Array<T,Eigen::Dynamic,1>& p_coord,
                                     const Eigen::Array<T,Eigen::Dynamic,1>& p_val)
  {
    if constexpr (std::is_same_v<T,double>)
    {
        return p_reg.getValue(p_coord, p_val);
    }
    else
    {
      if (auto p = dynamic_cast<const LocalLinearRegression*>(&p_reg))
        return p->template getValueAutoDiff<T>(p_coord,p_val);
       if (auto p = dynamic_cast<const LocalConstRegression*>(&p_reg))
        return p->template getValueAutoDiff<T>(p_coord,p_val);
       if (auto p = dynamic_cast<const GlobalRegression<Hermite>*>(&p_reg))
        return p->template getValueAutoDiff<T>(p_coord,p_val);
       if (auto p = dynamic_cast<const GlobalRegression<Canonical>*>(&p_reg))
        return p->template getValueAutoDiff<T>(p_coord,p_val);
       if (auto p = dynamic_cast<const GlobalRegression<Tchebychev>*>(&p_reg))
        return p->template getValueAutoDiff<T>(p_coord,p_val);
     
      // fallback
      throw std::runtime_error(" Regression not taken into account dispatchRegressionGetValue" ) ;
    }
}

template<typename T>
T dispatchRegressionGetAValue(const BaseRegression& p_reg,
                              const Eigen::Array<T,Eigen::Dynamic,1> &p_coordinates,
                              const Eigen::Array<T, Eigen::Dynamic, 1> &p_ptOfStock,
                              const std::vector< std::shared_ptr<InterpolatorSpectral<T>> > &p_interpFuncBasis)
  {
    if constexpr (std::is_same_v<T,double>)
    {
        return p_reg.getAValue(p_coordinates, p_ptOfStock,p_interpFuncBasis);
    }
    else
    {
     
      if (auto p = dynamic_cast<const LocalLinearRegression*>(&p_reg))
        return p->template getAValueAutoDiff<T>(p_coordinates, p_ptOfStock,p_interpFuncBasis);
      if (auto p = dynamic_cast<const LocalConstRegression*>(&p_reg))
        return p->template getAValueAutoDiff<T>(p_coordinates, p_ptOfStock,p_interpFuncBasis);
      if (auto p = dynamic_cast<const GlobalRegression<Hermite>*>(&p_reg))
        return p->template getAValueAutoDiff<T>(p_coordinates,p_ptOfStock,p_interpFuncBasis);
      if (auto p = dynamic_cast<const GlobalRegression<Canonical>*>(&p_reg))
        return p->template getAValueAutoDiff<T>(p_coordinates,p_ptOfStock,p_interpFuncBasis);
      if (auto p = dynamic_cast<const GlobalRegression<Tchebychev>*>(&p_reg))
        return p->template getAValueAutoDiff<T>(p_coordinates,p_ptOfStock,p_interpFuncBasis);

      // fallback
      throw std::runtime_error(" Regression not taken into account dispatchRegressionGetAValue" ) ;
 
    }
}
 

}
