import urllib

from framework.exceptions import HTTPError

from website.util.client import BaseClient
from addons.bitbucket import settings


class BitbucketClient(BaseClient):

    def __init__(self, access_token=None):
        self.access_token = access_token

    @property
    def _default_headers(self):
        if self.access_token:
            return {'Authorization': 'Bearer {}'.format(self.access_token)}
        return {}

    @property
    def username(self):
        return self.user()['username']

    def user(self):
        """Fetch the user identified by ``self.access_token``.

        API docs::

        * https://developer.atlassian.com/bitbucket/api/2/reference/resource/user

        :rtype: dict
        :return: a metadata object representing the user
        """
        res = self._make_request(
            'GET',
            self._build_url(settings.BITBUCKET_V2_API_URL, 'user'),
            expects=(200, ),
            throws=HTTPError(401)
        )
        return res.json()

    def repo(self, user, repo):
        """Get a single Bitbucket repo's info.

        API docs::

        * https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D

        :param str user: Bitbucket user name
        :param str repo: Bitbucket repo name
        :return: Dict of repo information
        """
        res = self._make_request(
            'GET',
            self._build_url(settings.BITBUCKET_V2_API_URL, 'repositories', user, repo),
            expects=(200, 404, ),
            throws=HTTPError(401)
        )
        return None if res.status_code == 404 else res.json()

    def repos(self):
        """Return a list of repository objects owned by the user

        API docs::

        * https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D

        :rtype:
        :return: list of repository objects
        """
        res = self._make_request(
            'GET',
            self._build_url(settings.BITBUCKET_V2_API_URL, 'repositories', self.username),
            expects=(200, ),
            throws=HTTPError(401),
            params={'pagelen': 100}
        )
        return res.json()['values']

    def team_repos(self):
        """Return a list of repositories owned by teams the user is a member of.

        API docs::

        * https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams

        * https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams/%7Busername%7D/repositories

        :rtype: list
        :return: a list of repository objects
        """

        res = self._make_request(
            'GET',
            self._build_url(settings.BITBUCKET_V2_API_URL, 'teams') + '?role=member',
            expects=(200, ),
            throws=HTTPError(401),
            params={'pagelen': 100}
        )
        teams = [x['username'] for x in res.json()['values']]

        team_repos = []
        for team in teams:
            res = self._make_request(
                'GET',
                self._build_url(settings.BITBUCKET_V2_API_URL, 'teams', team, 'repositories'),
                expects=(200, ),
                throws=HTTPError(401)
            )
            team_repos.extend(res.json()['values'])

        return team_repos

    def repo_default_branch(self, user, repo):
        """Return the default branch for a BB repository (what they call the
        "main branch").  They do not provide this via their v2 API,
        but there is a v1 endpoint that will return it.

        API doc:
        https://confluence.atlassian.com/bitbucket/repository-resource-1-0-296095202.html#repositoryResource1.0-GETtherepository%27smainbranch

        :param str user: Bitbucket user name
        :param str repo: Bitbucket repo name
        :rtype str:
        :return: name of the main branch

        """
        res = self._make_request(
            'GET',
            self._build_url(settings.BITBUCKET_V1_API_URL, 'repositories', user, repo, 'main-branch'),
            expects=(200, ),
            throws=HTTPError(401)
        )
        return res.json()['name']

    def branches(self, user, repo):
        """List a repo's branches.  This endpoint is paginated and may require
        multiple requests.

        API docs::

        * https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/refs/branches

        :param str user: Bitbucket user name
        :param str repo: Bitbucket repo name
        :return: List of branch dicts
        """
        branches, page_nbr = [], 1
        while True:
            url = self._build_url(settings.BITBUCKET_V2_API_URL, 'repositories', user, repo,
                                  'refs', 'branches')
            url = '{}?page={}'.format(url, page_nbr)
            res = self._make_request(
                'GET',
                url,
                expects=(200, ),
                throws=HTTPError(401)
            )
            res_data = res.json()
            branches.extend(res_data['values'])
            page_nbr += 1
            if not res_data.get('next', None):
                break
        return branches


def ref_to_params(branch=None, sha=None):

    params = urllib.urlencode({
        key: value
        for key, value in {'branch': branch, 'sha': sha}.iteritems()
        if value
    })
    if params:
        return '?' + params
    return ''

@@ -4612,51 +4612,14 @@
 ches
-, page_nbr = %5B%5D, 1%0A        while True:%0A    
+ = %5B%5D%0A
     
@@ -4706,115 +4706,48 @@
 epo,
-%0A                                  'refs', 'branches')%0A            url = '%7B%7D?page=%7B%7D'.format(url, page_nbr)
+ 'refs', 'branches')%0A        while True:
 %0A   
@@ -5008,40 +5008,13 @@
     
-page_nbr += 1%0A            if not
+url =
  res
@@ -5032,24 +5032,47 @@
 next', None)
+%0A            if not url
 :%0A          

update pagination for bitbucket's new non-sequential page numbering system