from mock import patch

import pytest
from flask_principal import AnonymousIdentity

from endpoints.api import api
from endpoints.api.organization import OrganizationCollaboratorList
from endpoints.api.repositorynotification import RepositoryNotification
from endpoints.api.permission import RepositoryUserTransitivePermission
from endpoints.api.team import OrganizationTeamSyncing
from endpoints.api.test.shared import conduct_api_call
from endpoints.api.repository import RepositoryTrust
from endpoints.api.signing import RepositorySignatures
from endpoints.api.search import ConductRepositorySearch
from endpoints.api.superuser import SuperUserRepositoryBuildLogs, SuperUserRepositoryBuildResource
from endpoints.api.superuser import SuperUserRepositoryBuildStatus
from endpoints.api.appspecifictokens import AppTokens, AppToken
from endpoints.api.trigger import BuildTrigger
from endpoints.test.shared import client_with_identity, toggle_feature

from test.fixtures import *

ORG_PARAMS = {'orgname': 'buynlarge'}
TEAM_PARAMS = {'orgname': 'buynlarge', 'teamname': 'owners'}
BUILD_PARAMS = {'build_uuid': 'test-1234'}
REPO_PARAMS = {'repository': 'devtable/someapp'}
SEARCH_PARAMS = {'query': ''}
NOTIFICATION_PARAMS = {'namespace': 'devtable', 'repository': 'devtable/simple', 'uuid': 'some uuid'}
TOKEN_PARAMS = {'token_uuid': 'someuuid'}
TRIGGER_PARAMS = {'repository': 'devtable/simple', 'trigger_uuid': 'someuuid'}

@pytest.mark.parametrize('resource,method,params,body,identity,expected', [
  (AppTokens, 'GET', {}, {}, None, 401),
  (AppTokens, 'GET', {}, {}, 'freshuser', 200),
  (AppTokens, 'GET', {}, {}, 'reader', 200),
  (AppTokens, 'GET', {}, {}, 'devtable', 200),

  (AppTokens, 'POST', {}, {}, None, 403),
  (AppTokens, 'POST', {}, {}, 'freshuser', 400),
  (AppTokens, 'POST', {}, {}, 'reader', 400),
  (AppTokens, 'POST', {}, {}, 'devtable', 400),

  (AppToken, 'GET', TOKEN_PARAMS, {}, None, 401),
  (AppToken, 'GET', TOKEN_PARAMS, {}, 'freshuser', 404),
  (AppToken, 'GET', TOKEN_PARAMS, {}, 'reader', 404),
  (AppToken, 'GET', TOKEN_PARAMS, {}, 'devtable', 404),

  (AppToken, 'DELETE', TOKEN_PARAMS, {}, None, 403),
  (AppToken, 'DELETE', TOKEN_PARAMS, {}, 'freshuser', 404),
  (AppToken, 'DELETE', TOKEN_PARAMS, {}, 'reader', 404),
  (AppToken, 'DELETE', TOKEN_PARAMS, {}, 'devtable', 404),

  (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, None, 401),
  (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'freshuser', 403),
  (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'reader', 403),
  (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'devtable', 200),

  (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, None, 403),
  (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'freshuser', 403),
  (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'reader', 403),
  (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'devtable', 400),

  (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, None, 403),
  (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'freshuser', 403),
  (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'reader', 403),
  (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'devtable', 200),

  (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, None, 200),
  (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'freshuser', 200),
  (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'reader', 200),
  (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'devtable', 200),

  (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, None, 401),
  (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'freshuser', 403),
  (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'reader', 403),
  (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'devtable', 400),

  (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, None, 401),
  (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'freshuser', 403),
  (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'reader', 403),
  (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'devtable', 400),

  (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, None, 401),
  (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'freshuser', 403),
  (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'reader', 403),
  (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None,  'devtable', 404),

  (RepositorySignatures, 'GET', REPO_PARAMS, {}, 'freshuser', 403),
  (RepositorySignatures, 'GET', REPO_PARAMS, {}, 'reader', 403),
  (RepositorySignatures, 'GET', REPO_PARAMS, {}, 'devtable', 404),

  (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, None, 403),
  (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'freshuser', 403),
  (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'reader', 403),
  (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'devtable', 400),

  (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, None, 403),
  (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'freshuser', 403),
  (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'reader', 403),
  (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'devtable', 404),

  (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, None, 401),
  (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'freshuser', 403),
  (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'reader', 403),
  (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'devtable', 404),

  (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, None, 403),
  (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'freshuser', 403),
  (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'reader', 403),
  (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'devtable', 404),

  (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, None, 403),
  (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'freshuser', 403),
  (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'reader', 403),
  (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'devtable', 400),

  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, None, 401),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'freshuser', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'reader', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'devtable', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, None, 401),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'freshuser', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'reader', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'devtable', 404),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, None, 401),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'freshuser', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'reader', 403),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'devtable', 404),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'devtable','repository': 'devtable/shared'}, None, 'devtable', 200),
  (RepositoryUserTransitivePermission, 'GET', {'username': 'devtable','repository': 'devtable/nope'}, None, 'devtable', 404),
])
def test_api_security(resource, method, params, body, identity, expected, client):
  with client_with_identity(identity, client) as cl:
    conduct_api_call(cl, resource, method, params, body, expected)


@pytest.mark.parametrize('is_superuser', [
  (True),
  (False),
])
@pytest.mark.parametrize('allow_nonsuperuser', [
  (True),
  (False),
])
@pytest.mark.parametrize('method, expected', [
  ('POST', 400),
  ('DELETE', 200),
])
def test_team_sync_security(is_superuser, allow_nonsuperuser, method, expected, client):
  def is_superuser_method(_):
    return is_superuser

  with patch('auth.permissions.superusers.is_superuser', is_superuser_method):
    with toggle_feature('NONSUPERUSER_TEAM_SYNCING_SETUP', allow_nonsuperuser):
      with client_with_identity('devtable', client) as cl:
        expect_success = is_superuser or allow_nonsuperuser
        expected_status = expected if expect_success else 403
        conduct_api_call(cl, OrganizationTeamSyncing, method, TEAM_PARAMS, {}, expected_status)