#include <array>
#include <bitset>
#include <iostream>
#include <booluarray.hpp>


#include <cstddef>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include "bernstein.hpp"
#include "multiloop.hpp"
#include "quadrature_multipoly.hpp"
#include "binomial.hpp"

#include "real.hpp"
#include "uvector.hpp"
#include "vector"
#include "xarray.hpp"
#include <chrono>
#include <cmath>
#include <memory>

#include "organizer/primitive.hpp"

namespace algoim::Organizer
{
class BasicTask
{
public:
    std::vector<BernsteinPrimitive> primitives;

    BasicTask(std::vector<std::shared_ptr<Primitive>> ps) {};

    BasicTask(std::shared_ptr<Primitive> p)
    {
        int      q         = 20;
        real     volume    = 0;
        real     xmin      = -1;
        real     xmax      = 1;
        auto     integrand = [](const uvector<real, 3>& x) { return 1.0; };
        uvector3 range     = xmax - xmin;


        if (auto pt = std::dynamic_pointer_cast<PowerTensor>(p)) {
            detail::powerTransformation(range, xmin, pt->tensor);
            auto primitive = BernsteinTensor(*pt);

            uvector<real, 3> testX(0., 0., 0.25);
            real             testEvalBernstein = bernstein::evalBernsteinPoly(primitive.tensor, testX);
            // auto             vec1              = xarray2StdVector(phi);
            std::cout << "eval bernstein without interpolation:" << testEvalBernstein << std::endl;

            ImplicitPolyQuadrature<3> ipquad(primitive.tensor);
            ipquad.integrate(AutoMixed, q, [&](const uvector<real, 3>& x, real w) {
                if (primitive.isInside(x)) volume += w * integrand(xmin + x * (xmax - xmin));
            });
        } else if (auto pc = std::dynamic_pointer_cast<PowerTensorComplex>(p)) {
            detail::powerTransformation(range, xmin, pc->compositeTensor);
            auto                      primitive = BernsteinTensorComplex(*pc);
            ImplicitPolyQuadrature<3> ipquad(primitive.compositeTensor);
            ipquad.integrate(AutoMixed, q, [&](const uvector<real, 3>& x, real w) {
                if (primitive.isInside(x)) volume += w * integrand(xmin + x * (xmax - xmin));
            });
        }
        volume *= pow(xmax - xmin, 3);
        std::cout << "Volume xxx: " << volume << std::endl;
    };

    // BasicTask(std::shared_ptr<PowerTensorComplex> pc)
    // {
    //     int      q = 10;
    //     real     volume;
    //     uvector3 xmin      = 0;
    //     uvector3 xmax      = 1;
    //     auto     integrand = [](const uvector<real, 3>& x) { return 1.0; };
    //     uvector3 range     = xmax - xmin;

    //     detail::powerTransformation(range, xmin, pc->compositeTensor);
    //     auto                      primitive = BernsteinTensorComplex(*pc);
    //     ImplicitPolyQuadrature<3> ipquad(primitive.compositeTensor);
    //     ipquad.integrate(AutoMixed, q, [&](const uvector<real, 3>& x, real w) {
    //         if (primitive.isInside(x)) volume += w * integrand(xmin + x * (xmax - xmin));
    //     });
    //     std::cout << "Volume xxx: " << volume << std::endl;
    // };
};
}; // namespace algoim::Organizer