from . import osmapi_test
import osmapi
from unittest import mock
import datetime


class TestOsmApiRelation(osmapi_test.TestOsmApi):
    def test_RelationGet(self):
        self._session_mock()

        result = self.api.RelationGet(321)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(args[1], self.api_base + "/api/0.6/relation/321")

        self.assertEqual(
            result,
            {
                "id": 321,
                "changeset": 434,
                "uid": 12,
                "timestamp": datetime.datetime(2009, 9, 15, 22, 24, 25),
                "visible": True,
                "version": 1,
                "user": "green525",
                "tag": {
                    "admin_level": "9",
                    "boundary": "administrative",
                    "type": "multipolygon",
                },
                "member": [
                    {"ref": 6908, "role": "outer", "type": "way"},
                    {"ref": 6352, "role": "outer", "type": "way"},
                    {"ref": 5669, "role": "outer", "type": "way"},
                    {"ref": 5682, "role": "outer", "type": "way"},
                    {"ref": 6909, "role": "outer", "type": "way"},
                    {"ref": 6355, "role": "outer", "type": "way"},
                    {"ref": 6910, "role": "outer", "type": "way"},
                    {"ref": 6911, "role": "outer", "type": "way"},
                    {"ref": 6912, "role": "outer", "type": "way"},
                ],
            },
        )

    def test_RelationGet_with_version(self):
        self._session_mock()

        result = self.api.RelationGet(765, 2)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(args[1], self.api_base + "/api/0.6/relation/765/2")

        self.assertEqual(result["id"], 765)
        self.assertEqual(result["changeset"], 41378)
        self.assertEqual(result["user"], "metaodi")
        self.assertEqual(result["tag"]["source"], "test")

    def test_RelationCreate(self):
        self._session_mock(auth=True)

        # setup mock
        self.api.ChangesetCreate = mock.Mock(return_value=3333)
        self.api._CurrentChangesetId = 3333

        test_relation = {
            "tag": {
                "type": "test",
            },
            "member": [
                {"ref": 6908, "role": "outer", "type": "way"},
                {"ref": 6352, "role": "point", "type": "node"},
            ],
        }

        cs = self.api.ChangesetCreate({"comment": "This is a test relation"})
        self.assertEqual(cs, 3333)

        result = self.api.RelationCreate(test_relation)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "PUT")
        self.assertEqual(args[1], self.api_base + "/api/0.6/relation/create")

        self.assertEqual(result["id"], 8989)
        self.assertEqual(result["version"], 1)
        self.assertEqual(result["member"], test_relation["member"])
        self.assertEqual(result["tag"], test_relation["tag"])

    def test_RelationCreate_existing_node(self):
        # setup mock
        self.api.ChangesetCreate = mock.Mock(return_value=1111)
        self.api._CurrentChangesetId = 1111

        test_relation = {
            "id": 456,
            "tag": {
                "type": "test",
            },
            "member": [
                {"ref": 6908, "role": "outer", "type": "way"},
                {"ref": 6352, "role": "point", "type": "node"},
            ],
        }

        with self.assertRaisesRegex(
            osmapi.OsmTypeAlreadyExistsError, "This relation already exists"
        ):
            self.api.RelationCreate(test_relation)

    def test_RelationUpdate(self):
        self._session_mock(auth=True)

        # setup mock
        self.api.ChangesetCreate = mock.Mock(return_value=3333)
        self.api._CurrentChangesetId = 3333

        test_relation = {
            "id": 8989,
            "tag": {
                "type": "test update",
            },
            "member": [{"ref": 6908, "role": "outer", "type": "way"}],
        }

        cs = self.api.ChangesetCreate({"comment": "This is a test relation"})
        self.assertEqual(cs, 3333)

        result = self.api.RelationUpdate(test_relation)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "PUT")
        self.assertEqual(args[1], self.api_base + "/api/0.6/relation/8989")

        self.assertEqual(result["id"], 8989)
        self.assertEqual(result["version"], 42)
        self.assertEqual(result["member"], test_relation["member"])
        self.assertEqual(result["tag"], test_relation["tag"])

    def test_RelationDelete(self):
        self._session_mock(auth=True)

        # setup mock
        self.api.ChangesetCreate = mock.Mock(return_value=3333)
        self.api._CurrentChangesetId = 3333

        test_relation = {"id": 8989}

        cs = self.api.ChangesetCreate({"comment": "This is a test relation"})
        self.assertEqual(cs, 3333)

        result = self.api.RelationDelete(test_relation)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "DELETE")
        self.assertEqual(args[1], self.api_base + "/api/0.6/relation/8989")

        self.assertEqual(result["id"], 8989)
        self.assertEqual(result["version"], 43)

    def test_RelationHistory(self):
        self._session_mock()

        result = self.api.RelationHistory(2470397)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(args[1], f"{self.api_base}/api/0.6/relation/2470397/history")

        self.assertEqual(len(result), 2)
        self.assertEqual(result[1]["id"], 2470397)
        self.assertEqual(result[1]["version"], 1)
        self.assertEqual(
            result[1]["tag"],
            {
                "restriction": "only_straight_on",
                "type": "restriction",
            },
        )
        self.assertEqual(result[2]["version"], 2)

    def test_RelationRelations(self):
        self._session_mock()

        result = self.api.RelationRelations(1532552)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(args[1], f"{self.api_base}/api/0.6/relation/1532552/relations")

        self.assertEqual(len(result), 1)
        self.assertEqual(result[0]["id"], 1532553)
        self.assertEqual(result[0]["version"], 85)
        self.assertEqual(len(result[0]["member"]), 120)
        self.assertEqual(result[0]["tag"]["type"], "network")
        self.assertEqual(result[0]["tag"]["name"], "Aargauischer Radroutennetz")

    def test_RelationRelationsUnusedElement(self):
        self._session_mock()

        result = self.api.RelationRelations(1532552)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(args[1], f"{self.api_base}/api/0.6/relation/1532552/relations")

        self.assertEqual(len(result), 0)
        self.assertIsInstance(result, list)

    def test_RelationFull(self):
        self._session_mock()

        result = self.api.RelationFull(2470397)

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(args[1], f"{self.api_base}/api/0.6/relation/2470397/full")

        self.assertEqual(len(result), 11)
        self.assertEqual(result[1]["data"]["id"], 101142277)
        self.assertEqual(result[1]["data"]["version"], 8)
        self.assertEqual(result[1]["type"], "node")
        self.assertEqual(result[10]["data"]["id"], 2470397)
        self.assertEqual(result[10]["data"]["version"], 2)
        self.assertEqual(result[10]["type"], "relation")

    def test_RelationsGet(self):
        self._session_mock()

        result = self.api.RelationsGet([1532552, 1532553])

        args, kwargs = self.session_mock.request.call_args
        self.assertEqual(args[0], "GET")
        self.assertEqual(
            args[1], f"{self.api_base}/api/0.6/relations?relations=1532552,1532553"
        )

        self.assertEqual(len(result), 2)
        self.assertEqual(result[1532553]["id"], 1532553)
        self.assertEqual(result[1532553]["version"], 85)
        self.assertEqual(result[1532553]["user"], "SimonPoole")
        self.assertEqual(result[1532552]["id"], 1532552)
        self.assertEqual(result[1532552]["visible"], True)
        self.assertEqual(result[1532552]["tag"]["route"], "bicycle")

    def test_RelationFull_with_deleted_relation(self):
        self._session_mock(filenames=[], status=410)

        with self.assertRaises(osmapi.ElementDeletedApiError) as context:
            self.api.RelationFull(2911456)
        self.assertEqual(410, context.exception.status)
