from collections import namedtuple
import features
import re

Scope = namedtuple('scope', ['scope', 'icon', 'dangerous', 'title', 'description'])


READ_REPO = Scope(scope='repo:read',
                  icon='fa-hdd-o',
                  dangerous=False,
                  title='View all visible repositories',
                  description=('This application will be able to view and pull all repositories '
                               'visible to the granting user or robot account'))

WRITE_REPO = Scope(scope='repo:write',
                   icon='fa-hdd-o',
                   dangerous=False,
                   title='Read/Write to any accessible repositories',
                   description=('This application will be able to view, push and pull to all '
                                'repositories to which the granting user or robot account has '
                                'write access'))

ADMIN_REPO = Scope(scope='repo:admin',
                   icon='fa-hdd-o',
                   dangerous=False,
                   title='Administer Repositories',
                   description=('This application will have administrator access to all '
                                'repositories to which the granting user or robot account has '
                                'access'))

CREATE_REPO = Scope(scope='repo:create',
                    icon='fa-plus',
                    dangerous=False,
                    title='Create Repositories',
                    description=('This application will be able to create repositories in to any '
                                 'namespaces that the granting user or robot account is allowed '
                                 'to create repositories'))

READ_USER = Scope(scope= 'user:read',
                  icon='fa-user',
                  dangerous=False,
                  title='Read User Information',
                  description=('This application will be able to read user information such as '
                               'username and email address.'))

ORG_ADMIN = Scope(scope='org:admin',
                  icon='fa-gear',
                  dangerous=True,
                  title='Administer Organization',
                  description=('This application will be able to administer your organizations '
                               'including creating robots, creating teams, adjusting team '
                               'membership, and changing billing settings. You should have '
                               'absolute trust in the requesting application before granting this '
                               'permission.'))

DIRECT_LOGIN = Scope(scope='direct_user_login',
                     icon='fa-exclamation-triangle',
                     dangerous=True,
                     title='Full Access',
                     description=('This scope should not be available to OAuth applications. '
                                  'Never approve a request for this scope!'))

SUPERUSER = Scope(scope='super:user',
                  icon='fa-street-view',
                  dangerous=True,
                  title='Super User Access',
                  description=('This application will be able to administer your installation '
                               'including managing users, managing organizations and other '
                               'features found in the superuser panel. You should have '
                               'absolute trust in the requesting application before granting this '
                               'permission.'))

ALL_SCOPES = {scope.scope: scope for scope in (READ_REPO, WRITE_REPO, ADMIN_REPO, CREATE_REPO,
                                               READ_USER, ORG_ADMIN, SUPERUSER)}

IMPLIED_SCOPES = {
  ADMIN_REPO: {ADMIN_REPO, WRITE_REPO, READ_REPO},
  WRITE_REPO: {WRITE_REPO, READ_REPO},
  READ_REPO: {READ_REPO},
  CREATE_REPO: {CREATE_REPO},
  READ_USER: {READ_USER},
  ORG_ADMIN: {ORG_ADMIN},
  SUPERUSER: {SUPERUSER},
  None: set(),
}


def app_scopes(app_config):
  if not app_config.get('FEATURE_SUPER_USERS', False):
    scopes_from_config = dict(ALL_SCOPES)
    del scopes_from_config[SUPERUSER.scope]
    return scopes_from_config
  return ALL_SCOPES


def scopes_from_scope_string(scopes):
  if not scopes:
    scopes = ''

  # Note: The scopes string should be space seperated according to the spec:
  # https://tools.ietf.org/html/rfc6749#section-3.3
  # However, we also support commas for backwards compatibility with existing callers to our code.
  scope_set = {ALL_SCOPES.get(scope, None) for scope in re.split(' |,', scopes)}
  return scope_set if not None in scope_set else set()


def validate_scope_string(scopes):
  decoded = scopes_from_scope_string(scopes)
  return len(decoded) > 0


def is_subset_string(full_string, expected_string):
  """ Returns true if the scopes found in expected_string are also found
      in full_string.
  """
  full_scopes = scopes_from_scope_string(full_string)
  if not full_scopes:
    return False

  full_implied_scopes = set.union(*[IMPLIED_SCOPES[scope] for scope in full_scopes])
  expected_scopes = scopes_from_scope_string(expected_string)
  return expected_scopes.issubset(full_implied_scopes)


def get_scope_information(scopes_string):
  scopes = scopes_from_scope_string(scopes_string)
  scope_info = []
  for scope in scopes:
    scope_info.append({
      'title': scope.title,
      'scope': scope.scope,
      'description': scope.description,
      'icon': scope.icon,
      'dangerous': scope.dangerous,
    })

  return scope_info