"""Organization Tests"""
import copy
import json
from os.path import join

import pytest
from hdx.utilities.dictandlist import merge_two_dictionaries
from hdx.utilities.loader import load_yaml

from hdx.api.configuration import Configuration
from hdx.data.hdxobject import HDXError
from hdx.data.organization import Organization
from hdx.data.user import User

from . import MockResponse, organization_data, user_data
from .test_user import user_mockshow

resultdict = load_yaml(
    join("tests", "fixtures", "organization_show_results.yml")
)

organization_list = [
    "acaps",
    "accion-contra-el-hambre-acf-spain",
    "acf-west-africa",
    "acled",
    "acted",
    "action-contre-la-faim",
    "adeso",
    "afd",
    "afdb",
    "afghanistan-protection-cluster",
]
searchdict = load_yaml(join("tests", "fixtures", "dataset_search_results.yml"))

organization_autocomplete = [
    {
        "title": "INNAGO",
        "id": "5a63012e-6c41-420c-8c33-e84b277fdc90",
        "name": "innago",
    }
]


def organization_mockshow(url, datadict):
    if "show" not in url:
        return MockResponse(
            404,
            '{"success": false, "error": {"message": "TEST ERROR: Not show", "__type": "TEST ERROR: Not Show Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_show"}',
        )
    result = json.dumps(resultdict)
    if (
        datadict["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19"
        or datadict["id"] == "TEST1"
    ):
        return MockResponse(
            200,
            '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_show"}'
            % result,
        )
    if datadict["id"] == "TEST2":
        return MockResponse(
            404,
            '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_show"}',
        )
    if datadict["id"] == "TEST3":
        return MockResponse(
            200,
            '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_show"}',
        )
    return MockResponse(
        404,
        '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_show"}',
    )


def mocklist(url):
    if "list" not in url:
        return MockResponse(
            404,
            '{"success": false, "error": {"message": "TEST ERROR: Not all", "__type": "TEST ERROR: Not All Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_list"}',
        )
    return MockResponse(
        200,
        '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_list"}'
        % json.dumps(organization_list),
    )


def mockgetdatasets(url, datadict):
    if "search" not in url:
        return MockResponse(
            404,
            '{"success": false, "error": {"message": "TEST ERROR: Not search", "__type": "TEST ERROR: Not Search Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=package_search"}',
        )
    if datadict["fq"] == "organization:acled":
        return MockResponse(
            200,
            '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=package_search"}'
            % json.dumps(searchdict),
        )


class TestOrganization:
    @pytest.fixture(scope="class")
    def static_yaml(self):
        return join(
            "tests", "fixtures", "config", "hdx_organization_static.yml"
        )

    @pytest.fixture(scope="class")
    def static_json(self):
        return join(
            "tests", "fixtures", "config", "hdx_organization_static.json"
        )

    @pytest.fixture(scope="function")
    def read(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                datadict = json.loads(data.decode("utf-8"))
                return organization_mockshow(url, datadict)

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def post_create(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                datadict = json.loads(data.decode("utf-8"))
                if "show" in url:
                    return organization_mockshow(url, datadict)
                if "create" not in url:
                    return MockResponse(
                        404,
                        '{"success": false, "error": {"message": "TEST ERROR: Not create", "__type": "TEST ERROR: Not Create Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_create"}',
                    )

                resultdictcopy = copy.deepcopy(resultdict)
                resultdictcopy["state"] = datadict["state"]
                result = json.dumps(resultdictcopy)
                if datadict["name"] == "MyOrganization1":
                    return MockResponse(
                        200,
                        '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_create"}'
                        % result,
                    )
                if datadict["name"] == "MyOrganization2":
                    return MockResponse(
                        404,
                        '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_create"}',
                    )
                if datadict["name"] == "MyOrganization3":
                    return MockResponse(
                        200,
                        '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_create"}',
                    )

                return MockResponse(
                    404,
                    '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_create"}',
                )

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def post_update(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                datadict = json.loads(data.decode("utf-8"))
                if "show" in url:
                    return organization_mockshow(url, datadict)
                if "update" not in url:
                    return MockResponse(
                        404,
                        '{"success": false, "error": {"message": "TEST ERROR: Not update", "__type": "TEST ERROR: Not Update Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_update"}',
                    )
                resultdictcopy = copy.deepcopy(resultdict)
                merge_two_dictionaries(resultdictcopy, datadict)

                result = json.dumps(resultdictcopy)
                if datadict["name"] == "MyOrganization1":
                    return MockResponse(
                        200,
                        '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_update"}'
                        % result,
                    )
                if datadict["name"] == "MyOrganization2":
                    return MockResponse(
                        404,
                        '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_update"}',
                    )
                if datadict["name"] == "MyOrganization3":
                    return MockResponse(
                        200,
                        '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_update"}',
                    )

                return MockResponse(
                    404,
                    '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_update"}',
                )

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def post_delete(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                decodedata = data.decode("utf-8")
                datadict = json.loads(decodedata)
                if "show" in url:
                    return organization_mockshow(url, datadict)
                if "delete" not in url:
                    return MockResponse(
                        404,
                        '{"success": false, "error": {"message": "TEST ERROR: Not delete", "__type": "TEST ERROR: Not Delete Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_delete"}',
                    )
                if datadict["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19":
                    return MockResponse(
                        200,
                        '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_delete"}'
                        % decodedata,
                    )

                return MockResponse(
                    404,
                    '{"success": false, "error": {"message": "Not found", "__type": "Not Found Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_delete"}',
                )

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def post_list(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                json.loads(data.decode("utf-8"))
                return mocklist(url)

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def user_read(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                datadict = json.loads(data.decode("utf-8"))
                return user_mockshow(url, datadict)

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def datasets_get(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                datadict = json.loads(data.decode("utf-8"))
                return mockgetdatasets(url, datadict)

        Configuration.read().remoteckan().session = MockSession()

    @pytest.fixture(scope="function")
    def post_autocomplete(self):
        class MockSession:
            @staticmethod
            def post(url, data, headers, files, allow_redirects, auth=None):
                decodedata = data.decode("utf-8")
                datadict = json.loads(decodedata)
                if "autocomplete" not in url or "innago" not in datadict["q"]:
                    return MockResponse(
                        404,
                        '{"success": false, "error": {"message": "TEST ERROR: Not autocomplete", "__type": "TEST ERROR: Not Autocomplete Error"}, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_autocomplete"}',
                    )
                result = json.dumps(organization_autocomplete)
                return MockResponse(
                    200,
                    '{"success": true, "result": %s, "help": "http://test-data.humdata.org/api/3/action/help_show?name=organization_autocomplete"}'
                    % result,
                )

        Configuration.read().remoteckan().session = MockSession()

    def test_read_from_hdx(self, configuration, read, mocksmtp):
        organization = Organization.read_from_hdx(
            "b67e6c74-c185-4f43-b561-0e114a736f19"
        )
        assert organization["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19"
        assert organization["name"] == "acled"
        organization = Organization.read_from_hdx("TEST2")
        assert organization is None
        organization = Organization.read_from_hdx("TEST3")
        assert organization is None

    def test_create_in_hdx(self, configuration, post_create):
        organization = Organization()
        with pytest.raises(HDXError):
            organization.create_in_hdx()
        organization["id"] = "b67e6c74-c185-4f43-b561-0e114a736f19"
        organization["name"] = "LALA"
        with pytest.raises(HDXError):
            organization.create_in_hdx()

        org_data = copy.deepcopy(organization_data)
        organization = Organization(org_data)
        organization.create_in_hdx()
        assert organization["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19"
        assert organization["state"] == "active"

        org_data["name"] = "MyOrganization2"
        organization = Organization(org_data)
        with pytest.raises(HDXError):
            organization.create_in_hdx()

        org_data["name"] = "MyOrganization3"
        organization = Organization(org_data)
        with pytest.raises(HDXError):
            organization.create_in_hdx()

    def test_update_in_hdx(self, configuration, post_update):
        organization = Organization()
        organization["id"] = "NOTEXIST"
        with pytest.raises(HDXError):
            organization.update_in_hdx()
        organization["name"] = "LALA"
        with pytest.raises(HDXError):
            organization.update_in_hdx()

        organization = Organization.read_from_hdx(
            "b67e6c74-c185-4f43-b561-0e114a736f19"
        )
        assert organization["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19"
        assert organization["name"] == "acled"

        organization["description"] = "Humanitarian work"
        organization["id"] = "b67e6c74-c185-4f43-b561-0e114a736f19"
        organization["name"] = "MyOrganization1"
        organization.update_in_hdx()
        assert organization["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19"
        assert organization["description"] == "Humanitarian work"
        assert organization["state"] == "active"

        organization["id"] = "NOTEXIST"
        with pytest.raises(HDXError):
            organization.update_in_hdx()

        del organization["id"]
        with pytest.raises(HDXError):
            organization.update_in_hdx()

        org_data = copy.deepcopy(organization_data)
        org_data["name"] = "MyOrganization1"
        org_data["id"] = "b67e6c74-c185-4f43-b561-0e114a736f19"
        organization = Organization(org_data)
        organization.create_in_hdx()
        assert organization["id"] == "b67e6c74-c185-4f43-b561-0e114a736f19"
        assert organization["name"] == "MyOrganization1"
        assert organization["state"] == "active"

    def test_delete_from_hdx(self, configuration, post_delete):
        organization = Organization.read_from_hdx(
            "b67e6c74-c185-4f43-b561-0e114a736f19"
        )
        organization.delete_from_hdx()
        del organization["id"]
        with pytest.raises(HDXError):
            organization.delete_from_hdx()

    def test_update_yaml(self, configuration, static_yaml):
        org_data = copy.deepcopy(organization_data)
        organization = Organization(org_data)
        assert organization["name"] == "MyOrganization1"
        assert organization["description"] == "We do humanitarian work"
        organization.update_from_yaml(static_yaml)
        assert organization["name"] == "MyOrg1"
        assert organization["description"] == "Humanitarian organisation"

    def test_update_json(self, configuration, static_json):
        org_data = copy.deepcopy(organization_data)
        organization = Organization(org_data)
        assert organization["name"] == "MyOrganization1"
        assert organization["description"] == "We do humanitarian work"
        organization.update_from_json(static_json)
        assert organization["name"] == "MyOrg1"
        assert organization["description"] == "other"

    def test_get_all_organizations(self, configuration, post_list):
        organizations = Organization.get_all_organization_names()
        assert len(organizations) == 10

    def test_users(self, configuration, user_read):
        org_data = copy.deepcopy(resultdict)
        organization = Organization(org_data)
        organization["users"][0]["name"] = "MyUser1"
        users = organization.get_users()
        assert len(users) == 1
        assert users[0]["name"] == "MyUser1"
        organization.remove_user("9f3e9973-7dbe-4c65-8820-f48578e3ffea")
        users = organization.get_users()
        assert len(users) == 0
        userdata_copy = copy.deepcopy(user_data)
        userdata_copy["id"] = "9f3e9973-7dbe-4c65-8820-f48578e3ffea"
        user = User(userdata_copy)
        user["name"] = "TEST1"
        user["capacity"] = "member"
        del organization["users"]
        organization.add_update_users([user])
        users = organization.get_users("member")
        assert len(users) == 1
        organization.remove_user(users[0])
        users = organization.get_users()
        assert len(users) == 0
        organization.add_update_users([user])
        users = organization.get_users("member")
        assert len(users) == 1
        organization.add_update_users(["MyUser1"], "member")
        users = organization.get_users("member")
        assert len(users) == 2
        assert users[0]["name"] == "MyUser1"
        organization.remove_user(users[0].data)
        users = organization.get_users("member")
        assert len(users) == 1
        organization.add_update_users([user], "editor")
        organization.remove_user("")
        users = organization.get_users("editor")
        assert len(users) == 1
        organization.remove_user("NOT_EXIST")
        users = organization.get_users("editor")
        assert len(users) == 1
        users = organization.get_users("admin")
        assert len(users) == 0
        del organization["users"][0]["id"]
        users = organization.get_users("member")
        assert len(users) == 1
        organization.add_update_user({"name": "TEST1"}, "member")
        users = organization.get_users("member")
        assert len(users) == 2
        with pytest.raises(HDXError):
            organization.add_update_users(123)
        with pytest.raises(HDXError):
            organization.add_update_user(123)
        with pytest.raises(HDXError):
            organization.remove_user(123)

    def test_get_datasets(self, configuration, datasets_get):
        org_data = copy.deepcopy(resultdict)
        organization = Organization(org_data)
        datasets = organization.get_datasets()
        assert len(datasets) == 10

    def test_autocomplete(self, configuration, post_autocomplete):
        assert Organization.autocomplete("innago") == organization_autocomplete
