#include "graph_creator.h"

#include <library/cpp/testing/gtest/gtest.h>
#include <maps/wikimap/mapspro/services/mrc/long_tasks/tasks_gen/lib/deadends.h>

namespace maps::mrc::gen_targets::tests {

TEST(deadends_tests, test_no_deadends)
{
    //  graph:
    //          --8->
    //          ^    |
    //          |    9
    //          7    |
    //          |    V
    //     --5-><-10--
    //     ^    |
    //     |    6
    //     4    |
    //     |    V
    //      <-2--

    GraphCreator graphCreator;
    graphCreator
        .addEdge(2, {1, 0}, {2, 0}, {4})
        .addEdge(4, {1, 0}, {1, 1}, {5})
        .addEdge(5, {1, 1}, {2, 1}, {6, 7})
        .addEdge(6, {2, 1}, {2, 0}, {2})
        .addEdge(7, {2, 1}, {2, 2}, {8})
        .addEdge(8, {2, 2}, {3, 2}, {9})
        .addEdge(9, {3, 2}, {3, 1}, {10})
        .addEdge(10, {3, 1}, {2, 1}, {7, 6});
    RoadNetworkData roadNetwork = graphCreator.createGraph();

    auto deadEndEdges = getDeadEnds(roadNetwork, {1});

    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre());
}

TEST(deadends_tests, test_deadends1)
{
    //  graph:
    //     --5->
    //     ^    |
    //     |    6
    //     4    |
    //     |    V
    //--1-> <-2-- --3->
    //<-7--       <-8--
    GraphCreator graphCreator;
    graphCreator
        .addEdge(1, {0, 0}, {1, 0}, {4, 7}, false)
        .addEdge(2, {2, 0}, {1, 0}, {4, 7})
        .addEdge(3, {2, 0}, {3, 0}, {8}, false)
        .addEdge(4, {1, 0}, {1, 1}, {5})
        .addEdge(5, {1, 1}, {2, 1}, {6})
        .addEdge(6, {2, 1}, {2, 0}, {2, 3})
        .addEdge(7, {1, 0}, {0, 0}, {1}, false)
        .addEdge(8, {3, 0}, {2, 0}, {2, 3});
    RoadNetworkData roadNetwork = graphCreator.createGraph();

    auto deadEndEdges = getDeadEnds(roadNetwork, {1});

    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7, 3, 8));
}

TEST(deadends_tests, test_deadends2)
{
    //  graph:
    //     --5->
    //     ^    |
    //     |    6
    //     4    |
    //     |    V
    //--1-> <-2-- --3->--9->
    //<-7--       <-8--<-10-
    GraphCreator graphCreator;
    graphCreator
        .addEdge(1, {0, 0}, {1, 0}, {4, 7}, false)
        .addEdge(2, {2, 0}, {1, 0}, {4, 7})
        .addEdge(3, {2, 0}, {3, 0}, {9}, false)
        .addEdge(4, {1, 0}, {1, 1}, {5})
        .addEdge(5, {1, 1}, {2, 1}, {6})
        .addEdge(6, {2, 1}, {2, 0}, {2, 3})
        .addEdge(7, {1, 0}, {0, 0}, {1}, false)
        .addEdge(8, {3, 0}, {2, 0}, {2, 3})
        .addEdge(9, {3, 0}, {4, 0}, {10})
        .addEdge(10, {4, 0}, {3, 0}, {8});
    RoadNetworkData roadNetwork = graphCreator.createGraph();

    auto deadEndEdges = getDeadEnds(roadNetwork, {4, 5});

    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7, 3, 8, 9, 10));
}

TEST(deadends_tests, test_deadends3)
{
    //  graph:
    //     --5->
    //     ^    |     ^
    //     |    6     |
    //     4    |     11
    //     |    V     |
    //--1-> <-2-- --3->--9->
    //<-7--       <-8--<-10-
    GraphCreator graphCreator;
    graphCreator
        .addEdge(1, {0, 0}, {1, 0}, {4, 7}, false)
        .addEdge(2, {2, 0}, {1, 0}, {4, 7})
        .addEdge(3, {2, 0}, {3, 0}, {9, 11}, false)
        .addEdge(4, {1, 0}, {1, 1}, {5})
        .addEdge(5, {1, 1}, {2, 1}, {6})
        .addEdge(6, {2, 1}, {2, 0}, {2, 3})
        .addEdge(7, {1, 0}, {0, 0}, {1}, false)
        .addEdge(8, {3, 0}, {2, 0}, {2, 3})
        .addEdge(9, {3, 0}, {4, 0}, {10})
        .addEdge(10, {4, 0}, {3, 0}, {8, 11})
        .addEdge(11, {3, 0}, {3, 1}, {});
    RoadNetworkData roadNetwork = graphCreator.createGraph();

    auto deadEndEdges = getDeadEnds(roadNetwork, {1, 2, 3});

    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7, 9, 10));
}

TEST(deadends_tests, test_deadend_with_big_fc)
{
    //  graph:
    //     --5->       -10->
    //     ^    |      ^   |
    //     |    6      |   11
    //     4    |      9   |
    //     |    V      |   |
    //--1-> <-2-- --3->    v
    //<-7--       <-8--<-12-
    GraphCreator graphCreator;
    graphCreator
        .addEdge(1, {0, 0}, {1, 0}, {4, 7}, false)
        .addEdge(2, {2, 0}, {1, 0}, {4, 7})
        .addEdge(3, {2, 0}, {3, 0}, {8, 9}, false)
        .addEdge(4, {1, 0}, {1, 1}, {5})
        .addEdge(5, {1, 1}, {2, 1}, {6})
        .addEdge(6, {2, 1}, {2, 0}, {2, 3})
        .addEdge(7, {1, 0}, {0, 0}, {1}, false)
        .addEdge(8, {3, 0}, {2, 0}, {2, 3})
        .addEdge(9, {3, 0}, {3, 1}, {10})
        .addEdge(10, {3, 1}, {4, 1}, {11})
        .addEdge(11, {4, 1}, {4, 0}, {12})
        .addEdge(12, {4, 0}, {3, 0}, {8});
    graphCreator.edges_[9].fc = 2;
    graphCreator.edges_[10].fc = 2;
    graphCreator.edges_[11].fc = 2;
    graphCreator.edges_[12].fc = 2;
    RoadNetworkData roadNetwork = graphCreator.createGraph();

    auto deadEndEdges = getDeadEnds(roadNetwork, {1, 2});
    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7));

    deadEndEdges = getDeadEnds(roadNetwork, {1});
    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7, 3, 8));

    graphCreator.edges_[12].fc = 0;
    roadNetwork = graphCreator.createGraph();
    deadEndEdges = getDeadEnds(roadNetwork, {1});
    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7));

    graphCreator.edges_[12].fc = 2;
    graphCreator.edges_[9].fc = 1;
    roadNetwork = graphCreator.createGraph();

    deadEndEdges = getDeadEnds(roadNetwork, {1});
    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7));
}

TEST(deadends_tests, test_deadend_with_big_fc2)
{
    //  graph:
    //     --5->            -10->
    //     ^    |     ^     ^   |
    //     |    6     |     |   11
    //     4    |     15    9   |
    //     |    V     |     |   |
    //--1-> <-2-- --3->-13->    v
    //<-7--       <-8--<-14-<-12-
    GraphCreator graphCreator;
    graphCreator
        .addEdge(1, {0, 0}, {1, 0}, {4, 7}, false)
        .addEdge(2, {2, 0}, {1, 0}, {4, 7})
        .addEdge(3, {2, 0}, {3, 0}, {8, 13, 15}, false)
        .addEdge(4, {1, 0}, {1, 1}, {5})
        .addEdge(5, {1, 1}, {2, 1}, {6})
        .addEdge(6, {2, 1}, {2, 0}, {2, 3})
        .addEdge(7, {1, 0}, {0, 0}, {1}, false)
        .addEdge(8, {3, 0}, {2, 0}, {2, 3})
        .addEdge(9, {4, 0}, {4, 1}, {10})
        .addEdge(10, {4, 1}, {5, 1}, {11})
        .addEdge(11, {5, 1}, {5, 0}, {12})
        .addEdge(12, {5, 0}, {4, 0}, {14})
        .addEdge(13, {3, 0}, {4, 0}, {9, 14})
        .addEdge(14, {4, 0}, {3, 0}, {8, 13, 15})
        .addEdge(15, {3, 0}, {3, 1}, {});
    graphCreator.edges_[9].fc = 2;
    graphCreator.edges_[10].fc = 2;
    graphCreator.edges_[11].fc = 2;
    graphCreator.edges_[12].fc = 2;
    graphCreator.edges_[15].fc = 2;
    RoadNetworkData roadNetwork = graphCreator.createGraph();

    auto deadEndEdges = getDeadEnds(roadNetwork, {1, 2});
    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7));

    deadEndEdges = getDeadEnds(roadNetwork, {1});
    EXPECT_THAT(deadEndEdges, testing::UnorderedElementsAre(1, 7, 3, 8, 13, 14));
}

} // namespace maps::mrc::gen_targets::tests
