import graphene
import pytest
from freezegun import freeze_time

from .....app.models import App
from .....webhook.models import Webhook
from ....tests.utils import assert_no_permission, get_graphql_content
from ...enums import AppTypeEnum

QUERY_APPS_WITH_FILTER = """
    query ($filter: AppFilterInput ){
        apps(first: 5, filter: $filter){
            edges{
                node{
                    id
                    isActive
                    permissions{
                        name
                        code
                    }
                    tokens{
                        authToken
                    }
                    webhooks{
                        name
                    }
                    name
                    type
                    aboutApp
                    dataPrivacy
                    dataPrivacyUrl
                    homepageUrl
                    supportUrl
                    configurationUrl
                    appUrl
                    extensions{
                        id
                        label
                        url
                        view
                        type
                        target
                        permissions{
                            code
                        }
                    }
                }
            }
        }
    }
    """


@pytest.mark.parametrize(
    "app_filter, count",
    (
        ({"search": "Sample"}, 1),
        ({"isActive": False}, 1),
        ({}, 2),
        ({"type": AppTypeEnum.THIRDPARTY.name}, 1),
        ({"type": AppTypeEnum.LOCAL.name}, 1),
    ),
)
def test_apps_query(
    staff_api_client,
    permission_manage_apps,
    permission_manage_orders,
    app_with_extensions,
    external_app,
    app_filter,
    count,
):
    app, app_extensions = app_with_extensions
    external_app.is_active = False
    external_app.save()
    webhooks = Webhook.objects.bulk_create(
        [
            Webhook(app=app, name="first", target_url="http://www.example.com/test"),
            Webhook(app=external_app, name="second", target_url="http://www.exa.com/s"),
        ]
    )
    webhooks_names = [w.name for w in webhooks]

    variables = {"filter": app_filter}
    response = staff_api_client.post_graphql(
        QUERY_APPS_WITH_FILTER,
        variables,
        permissions=[permission_manage_apps, permission_manage_orders],
    )
    content = get_graphql_content(response)

    apps_data = content["data"]["apps"]["edges"]
    for app_data in apps_data:
        tokens = app_data["node"]["tokens"]
        assert len(tokens) == 1
        assert len(tokens[0]["authToken"]) == 4
        webhooks = app_data["node"]["webhooks"]
        assert len(webhooks) == 1
        assert webhooks[0]["name"] in webhooks_names
    assert len(apps_data) == count


def test_apps_with_extensions_query(
    staff_api_client,
    permission_manage_apps,
    permission_manage_orders,
    app_with_extensions,
):
    # given
    app, app_extensions = app_with_extensions

    # when
    response = staff_api_client.post_graphql(
        QUERY_APPS_WITH_FILTER,
        permissions=[permission_manage_apps, permission_manage_orders],
    )

    # then
    content = get_graphql_content(response)

    apps_data = content["data"]["apps"]["edges"]

    assert len(apps_data) == 1
    app_data = apps_data[0]["node"]

    extensions_data = app_data["extensions"]
    returned_ids = {e["id"] for e in extensions_data}
    returned_labels = {e["label"] for e in extensions_data}
    returned_urls = {e["url"] for e in extensions_data}
    returned_views = {e["view"].lower() for e in extensions_data}
    returned_types = {e["type"].lower() for e in extensions_data}
    returned_targets = {e["target"].lower() for e in extensions_data}
    returned_permission_codes = [e["permissions"] for e in extensions_data]
    for app_extension in app_extensions:
        global_id = graphene.Node.to_global_id("AppExtension", app_extension.id)
        assert global_id in returned_ids
        assert app_extension.label in returned_labels
        assert app_extension.url in returned_urls
        assert app_extension.view in returned_views
        assert app_extension.type in returned_types
        assert app_extension.target in returned_targets
        assigned_permissions = [p.codename for p in app_extension.permissions.all()]
        assigned_permissions = [{"code": p.upper()} for p in assigned_permissions]
        assert assigned_permissions in returned_permission_codes


QUERY_APPS_WITH_SORT = """
    query ($sort_by: AppSortingInput!) {
        apps(first:5, sortBy: $sort_by) {
                edges{
                    node{
                        name
                    }
                }
            }
        }
"""


@pytest.mark.parametrize(
    "apps_sort, result_order",
    [
        ({"field": "NAME", "direction": "ASC"}, ["facebook", "google"]),
        ({"field": "NAME", "direction": "DESC"}, ["google", "facebook"]),
        ({"field": "CREATION_DATE", "direction": "ASC"}, ["google", "facebook"]),
        ({"field": "CREATION_DATE", "direction": "DESC"}, ["facebook", "google"]),
    ],
)
def test_query_apps_with_sort(
    apps_sort,
    result_order,
    staff_api_client,
    permission_manage_apps,
):
    with freeze_time("2018-05-31 12:00:01"):
        App.objects.create(name="google", is_active=True)
    with freeze_time("2019-05-31 12:00:01"):
        App.objects.create(name="facebook", is_active=True)
    variables = {"sort_by": apps_sort}
    staff_api_client.user.user_permissions.add(permission_manage_apps)
    response = staff_api_client.post_graphql(QUERY_APPS_WITH_SORT, variables)
    content = get_graphql_content(response)
    apps = content["data"]["apps"]["edges"]

    for order, account_name in enumerate(result_order):
        assert apps[order]["node"]["name"] == account_name


def test_apps_query_no_permission(
    staff_api_client, permission_manage_users, permission_manage_staff, app
):
    variables = {"filter": {}}
    response = staff_api_client.post_graphql(
        QUERY_APPS_WITH_FILTER, variables, permissions=[]
    )
    assert_no_permission(response)

    response = staff_api_client.post_graphql(
        QUERY_APPS_WITH_FILTER,
        variables,
        permissions=[permission_manage_users, permission_manage_staff],
    )
    assert_no_permission(response)
