#include <library/cpp/testing/gtest/gtest.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/feedback/include/privacy.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/location/include/rotation.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/unit_test/include/frame.h>

using namespace maps::mrc::db::eye;

namespace maps::mrc::eye::tests {

namespace {

HypothesisContext::Item makeSignContextItem(
    traffic_signs::TrafficSign signType,
    db::FeaturePrivacy privacy)
{
    return {
        db::eye::Object(
            db::TId(0),
            db::eye::SignAttrs{signType, false}
        ),
        db::eye::ObjectLocation(
            db::TId(0u),
            geolib3::Point2(0., 0.),
            toRotation(geolib3::Heading(0.0), identical)
        ),
        db::eye::Detection(
            db::TId(0),
            db::eye::DetectedSign{
                {100, 100, 200, 200},
                signType,
                0.9,
                false,
                0.95
            }
        ),
        db::eye::DetectionGroup(
            db::TId(0),
            db::eye::DetectionType::Sign
        ),
        db::eye::Frame(
            db::TId(0),
            identical,
            makeUrlContext(1, "cw0"),
            {1920, 1080},
            time()
        ),
        db::eye::FrameLocation(
            db::TId(0u),
            geolib3::Point2(0., 0.),
            toRotation(geolib3::Heading(0.0), identical)
        ),
        db::eye::FramePrivacy(
            db::TId(0), privacy
        )
    };
}

void testThrowException(
    const db::eye::Hypothesis& hypothesis,
    const HypothesisContext& context)
{
    std::stringstream ss;
    json::Builder builder(ss);
    builder << [&](json::ObjectBuilder b) {
        EXPECT_THROW(setHypothesisPrivacy(hypothesis, context, b), maps::Exception);
    };
}

void testIsPublicFeedback(
    const db::eye::Hypothesis& hypothesis,
    const HypothesisContext& context)
{
    std::stringstream ss;
    json::Builder builder(ss);
    builder << [&](json::ObjectBuilder b) {
        setHypothesisPrivacy(hypothesis, context, b);
    };
    json::Value result = json::Value::fromString(ss.str());

    ASSERT_TRUE(result.hasField("hidden"));
    EXPECT_EQ(result["hidden"].as<bool>(), false);
}

void testIsRestrictedFeedback(
    const db::eye::Hypothesis& hypothesis,
    const HypothesisContext& context)
{
    std::stringstream ss;
    json::Builder builder(ss);
    builder << [&](json::ObjectBuilder b) {
        setHypothesisPrivacy(hypothesis, context, b);
    };
    json::Value result = json::Value::fromString(ss.str());

    ASSERT_TRUE(result.hasField("hidden"));
    EXPECT_EQ(result["hidden"].as<bool>(), true);
}

void testIsSecretFeedback(
    const db::eye::Hypothesis& hypothesis,
    const HypothesisContext& context)
{
    std::stringstream ss;
    json::Builder builder(ss);
    builder << [&](json::ObjectBuilder b) {
        setHypothesisPrivacy(hypothesis, context, b);
    };
    json::Value result = json::Value::fromString(ss.str());

    ASSERT_TRUE(result.hasField("hidden"));
    EXPECT_EQ(result["hidden"].as<bool>(), true);
    ASSERT_TRUE(result.hasField("internalContent"));
    EXPECT_EQ(result["internalContent"].as<bool>(), true);
}

} // namespace

TEST(feedback_privacy_tests, throw_exception_with_empty_context_test)
{
    db::eye::Hypothesis hypothesis(
        geolib3::Point2(0, 0),
        db::eye::AbsentParkingAttrs()
    );
    HypothesisContext context({});

    testThrowException(hypothesis, context);
}

TEST(feedback_privacy_tests, public_hypothesis_with_public_frames_test)
{
    db::eye::Hypothesis hypothesis(
        geolib3::Point2(0, 0),
        db::eye::AbsentParkingAttrs()
    );
    HypothesisContext context({
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Public
        ),
    });

    testIsPublicFeedback(hypothesis, context);
}

TEST(feedback_privacy_tests, restricted_hypothesis_with_restricted_frame_test)
{
    db::eye::Hypothesis hypothesis(
        geolib3::Point2(0, 0),
        db::eye::AbsentParkingAttrs()
    );
    HypothesisContext context({
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Restricted
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Public
        ),
    });

    testIsRestrictedFeedback(hypothesis, context);
}

TEST(feedback_privacy_tests, secret_hypothesis_with_restricted_frame_test)
{
    db::eye::Hypothesis hypothesis(
        geolib3::Point2(0, 0),
        db::eye::AbsentParkingAttrs()
    );
    HypothesisContext context({
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Restricted
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::InformationParking,
            db::FeaturePrivacy::Secret
        ),
    });

    testIsSecretFeedback(hypothesis, context);
}

TEST(feedback_privacy_tests, restricted_traffic_sign_hypothesis_with_public_frames_test)
{
    db::eye::Hypothesis hypothesis(
        geolib3::Point2(0, 0),
        db::eye::TrafficSignAttrs{wiki::social::feedback::Type::TrafficProhibitedSign}
    );
    HypothesisContext context({
        makeSignContextItem(
            traffic_signs::TrafficSign::ProhibitoryNoEntry,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::ProhibitoryNoEntry,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::ProhibitoryNoEntry,
            db::FeaturePrivacy::Public
        ),
    });

    testIsRestrictedFeedback(hypothesis, context);
}

TEST(feedback_privacy_tests, secret_traffic_sign_hypothesis_with_secret_frames_test)
{
    db::eye::Hypothesis hypothesis(
        geolib3::Point2(0, 0),
        db::eye::TrafficSignAttrs{wiki::social::feedback::Type::TrafficProhibitedSign}
    );
    HypothesisContext context({
        makeSignContextItem(
            traffic_signs::TrafficSign::ProhibitoryNoEntry,
            db::FeaturePrivacy::Public
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::ProhibitoryNoEntry,
            db::FeaturePrivacy::Secret
        ),
        makeSignContextItem(
            traffic_signs::TrafficSign::ProhibitoryNoEntry,
            db::FeaturePrivacy::Public
        ),
    });

    testIsSecretFeedback(hypothesis, context);
}

} // namespace maps::mrc::eye::tests
