from collections import namedtuple


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!'))


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

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},
  None: set(),
}


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

  return {ALL_SCOPES.get(scope, None) for scope in scopes.split(',')}


def validate_scope_string(scopes):
  decoded = scopes_from_scope_string(scopes)
  return None not in decoded and 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)
  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:
    if scope:
      scope_info.append({
        'title': scope.title,
        'scope': scope.scope,
        'description': scope.description,
        'icon': scope.icon,
        'dangerous': scope.dangerous,
      })

  return scope_info
