/*
 * Copyright 2023 NWChemEx-Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "export_pluginplay.hpp"
#include <pluginplay/python/python.hpp>
#include <pluginplay/submodule_request.hpp>

namespace pluginplay {

void py_set_type(SubmoduleRequest& sr, py::object pt) {
    auto py_rtti   = pt.attr("type")();
    auto rtti      = py_rtti.cast<python::PyTypeInfo>().value();
    auto py_inputs = pt.attr("inputs")();
    sr.set_type(rtti, py_inputs.cast<type::input_map>());
}

bool py_satisfies_property_type(SubmoduleRequest& sr, py::object pt) {
    auto py_rtti = pt.attr("type")();
    auto rtti    = py_rtti.cast<python::PyTypeInfo>().value();
    return sr.satisfies_property_type(rtti);
}

auto py_sr_run_as(py::object sr, py::object pt, py::args args) {
    auto py_mod = sr.attr("value")();
    return py_mod.attr("run_as")(pt, *args);
}

void export_submodule_request(py_module_reference m) {
    using value_fxn = Module& (SubmoduleRequest::*)();

    py_class_type<SubmoduleRequest>(m, "SubmoduleRequest")
      .def(py::init<>())
      .def("has_type", &SubmoduleRequest::has_type)
      .def("has_module", &SubmoduleRequest::has_module)
      .def("has_description", &SubmoduleRequest::has_description)
      .def("has_name", &SubmoduleRequest::has_name)
      .def("ready", &SubmoduleRequest::ready)
      .def("set_type", &py_set_type)
      .def("satisfies_property_type", &py_satisfies_property_type)
      .def("set_description", &SubmoduleRequest::set_description)
      .def("submod_uuids", &SubmoduleRequest::submod_uuids)
      .def("uuid", &SubmoduleRequest::uuid)
      .def("value", static_cast<value_fxn>(&SubmoduleRequest::value))
      .def("description", &SubmoduleRequest::description)
      .def("get_name",
           [](SubmoduleRequest& self) {
               try {
                   return self.get_name();
               } catch(const std::bad_optional_access& e) {
                   throw std::runtime_error("No Name Set");
               }
           })
      .def("lock", &SubmoduleRequest::lock)
      .def("run_as", &py_sr_run_as)
      .def(py::self == py::self)
      .def(py::self != py::self);
}

} // namespace pluginplay
