#include "pyresultsviewer.h"

#include <yandex/maps/wiki/diffalert/storage/stored_message.h>
#include <yandex/maps/wiki/diffalert/storage/issue_creator.h>
#include <yandex/maps/wiki/common/date_time.h>
#include <yandex/maps/wiki/common/pyutils.hpp>

#include <boost/noncopyable.hpp>
#include <boost/python.hpp>

namespace bp = boost::python;
namespace common = maps::wiki::common;
namespace da = maps::wiki::diffalert;

namespace {

bp::str messageDescription(const da::StoredMessage& msg)
{ return bp::str(msg.description()); }

bp::str messageCategoryId(const da::StoredMessage& msg)
{ return bp::str(msg.categoryId()); }

bp::str messageObjectLabel(const da::StoredMessage& msg)
{
    return bp::str(msg.objectLabel());
}

bp::str messageInspectedAt(const da::StoredMessage& msg)
{
    return bp::str(
            common::canonicalDateTimeString(
                    msg.inspectedAt(), common::WithTimeZone::Yes));
}

bp::list messageMarkAsInspected(
        bp::object pgPool,
        bp::object messageIds,
        da::TUId uid)
{
    auto messageIdsVec = common::toVector<da::StoredMessageId>(messageIds);
    auto txn = bp::extract<maps::pgpool3::Pool&>(pgPool)()
        .masterWriteableTransaction();
    auto inspected = da::StoredMessage::markAsInspected(txn.get(), messageIdsVec, uid);
    txn->commit();
    return common::toPyList(inspected);
}

bp::object messagePostpone(
        bp::object pgPool,
        da::StoredMessageId messageId,
        da::PostponeAction action)
{
    auto txn = bp::extract<maps::pgpool3::Pool&>(pgPool)()
        .masterWriteableTransaction();
    auto postponed = da::StoredMessage::postpone(txn.get(), messageId, action);
    txn->commit();
    return bp::object(postponed);
}

std::string getOrCreateIssue(
    da::IssueCreator& issueCreator,
    bp::object pgPool,
    const da::StoredMessage& message,
    da::TId branchId,
    const std::string& login,
    const std::string& categoryGroup,
    const std::string& pageUrl)
{
    auto txn = bp::extract<maps::pgpool3::Pool&>(pgPool)()
        .masterWriteableTransaction();
    auto key = issueCreator.getOrCreateIssue(
        *txn, message, branchId, login, categoryGroup, pageUrl);
    txn->commit();
    return key;
}

} // namespace

BOOST_PYTHON_MODULE(diffalert)
{
    PyEval_InitThreads();
    using namespace maps::wiki::diffalert::python;

    bp::class_<da::Priority>
        ("Priority", bp::no_init)
        .def_readonly("major", &da::Priority::major)
        .def_readonly("minor", &da::Priority::minor)
        .def_readonly("sort", &da::Priority::sort);

    bp::enum_<da::PostponeAction>("PostponeAction")
        .value("POSTPONE", da::PostponeAction::Postpone)
        .value("RETURN", da::PostponeAction::Return);

    bp::enum_<da::SortKind>("SortKind")
        .value("BY_NAME", da::SortKind::ByName)
        .value("BY_SIZE", da::SortKind::BySize);

    bp::class_<da::StoredMessage>
        ("StoredMessage", bp::no_init)
        .add_property("id", &da::StoredMessage::id)
        .add_property("object_id", &da::StoredMessage::objectId)
        .add_property("priority", &da::StoredMessage::priority)
        .add_property("description", &messageDescription)
        .add_property("category_id", &messageCategoryId)
        .add_property("object_label", &messageObjectLabel)
        .add_property("inspected_by", &da::StoredMessage::inspectedBy)
        .add_property("inspected_at", &messageInspectedAt)
        .add_property("postponed", &da::StoredMessage::postponed)
        .def("mark_as_inspected", &messageMarkAsInspected,
            (bp::arg("pool"),
             bp::arg("message_ids"),
             bp::arg("uid")))
        .staticmethod("mark_as_inspected")
        .def("postpone", &messagePostpone,
            (bp::arg("pool"),
             bp::arg("message_id"),
             bp::arg("action")))
        .staticmethod("postpone");

    bp::class_<da::MessageStatisticsItem>
        ("MessageStatisticsItem", bp::no_init)
        .def_readonly("major_priority", &da::MessageStatisticsItem::majorPriority)
        .def_readonly("region_priority", &da::MessageStatisticsItem::regionPriority)
        .def_readonly("category_id", &da::MessageStatisticsItem::categoryId)
        .def_readonly("description", &da::MessageStatisticsItem::description)
        .def_readonly("total_count", &da::MessageStatisticsItem::totalCount)
        .def_readonly("inspected_count", &da::MessageStatisticsItem::inspectedCount);

    bp::class_<PyResultsViewer, boost::noncopyable>(
            "ResultsViewer",
            bp::init<da::TaskId, bp::object>(
                (bp::arg("task_id"),
                 bp::arg("pgpool"))))
        .add_property("task_id", &PyResultsViewer::taskId)
        .def("message_count", &PyResultsViewer::messageCount,
            (bp::arg("geom_wkb") = bp::object(),
             bp::arg("major_priority") = bp::object(),
             bp::arg("categories") = bp::object(),
             bp::arg("description") = bp::object(),
             bp::arg("region_priority") = bp::object(),
             bp::arg("postponed") = bp::object(),
             bp::arg("exclude_inspected_by") = bp::object()))
        .def("statistics", &PyResultsViewer::statistics,
            (bp::arg("geom_wkb") = bp::object(),
             bp::arg("major_priority") = bp::object(),
             bp::arg("region_priority") = bp::object(),
             bp::arg("postponed") = bp::object(),
             bp::arg("exclude_inspected_by") = bp::object()))
        .def("messages", &PyResultsViewer::messages,
            (bp::arg("sort_kind"),
             bp::arg("offset"),
             bp::arg("limit"),
             bp::arg("geom_wkb") = bp::object(),
             bp::arg("major_priority") = bp::object(),
             bp::arg("categories") = bp::object(),
             bp::arg("description") = bp::object(),
             bp::arg("region_priority") = bp::object(),
             bp::arg("postponed") = bp::object(),
             bp::arg("exclude_inspected_by") = bp::object()))
        .def("message_ids", &PyResultsViewer::messageIds,
            (bp::arg("geom_wkb") = bp::object(),
             bp::arg("major_priority") = bp::object(),
             bp::arg("categories") = bp::object(),
             bp::arg("description") = bp::object(),
             bp::arg("region_priority") = bp::object(),
             bp::arg("postponed") = bp::object(),
             bp::arg("exclude_inspected_by") = bp::object()))
        .def("message", &PyResultsViewer::message,
            (bp::arg("message_id")));

    bp::class_<da::IssueCreator, boost::noncopyable>(
        "IssueCreator",
            bp::init<std::string>())
        .def("get_or_create_issue", getOrCreateIssue, (
            bp::arg("pool"),
            bp::arg("message"),
            bp::arg("branch_id"),
            bp::arg("login"),
            bp::arg("category_group"),
            bp::arg("page_url")));
}
