import datetime
import json
from calendar import timegm
from urllib.parse import parse_qsl

import requests
from allauth.socialaccount import models as aamodels
from requests_oauthlib import OAuth1
from rest_framework import parsers, renderers
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler

from dss import settings
from spa.models import UserProfile
from spa.models.socialaccountlink import SocialAccountLink


def _temp_reverse_user(uid, provider, access_token, access_token_secret, payload):
    """
        Do some magic here to find user account and deprecate psa
        1. Look for account in
    """
    user = None
    try:
        sa = SocialAccountLink.objects.get(social_id=uid)
        sa.type = provider
        sa.social_id = uid
        sa.access_token = access_token
        sa.access_token_secret = access_token_secret
        sa.provider_data = payload
        sa.save()
        user = UserProfile.objects.get(id=sa.user.id)
    except SocialAccountLink.DoesNotExist:
        # try allauth
        try:
            aa = aamodels.SocialAccount.objects.get(uid=uid)
            try:
                user = UserProfile.objects.get(user__id=aa.user_id)
            except UserProfile.DoesNotExist:
                print('Need to create UserProfile')
            # we got an allauth, create the SocialAccountLink
            sa = SocialAccountLink()
            sa.user = user
            sa.social_id = aa.uid
            sa.type = aa.provider
            sa.access_token = access_token
            sa.access_token_secret = access_token_secret
            sa.provider_data = payload
            sa.save()
        except aamodels.SocialAccount.DoesNotExist:
            print('Need to create social model')

    return user if user else None


class SocialLoginHandler(APIView):
    """View to authenticate users through social media."""
    permission_classes = (AllowAny,)

    def post(self, request):
        uid = None
        backend = request.query_params.get('backend')
        user = None
        if backend in ['twitter']:
            request_token_url = 'https://api.twitter.com/oauth/request_token'
            access_token_url = 'https://api.twitter.com/oauth/access_token'
            access_token = ""
            access_token_secret = ""
            if request.data.get('oauth_token') and request.data.get('oauth_verifier'):
                auth = OAuth1(settings.SOCIAL_AUTH_TWITTER_KEY,
                              client_secret=settings.SOCIAL_AUTH_TWITTER_SECRET,
                              resource_owner_key=request.data.get('oauth_token'),
                              verifier=request.data.get('oauth_verifier'))
                r = requests.post(access_token_url, auth=auth)
                profile = dict(parse_qsl(r.text))
                payload = json.dumps(profile)
                uid = profile.get('user_id')
                access_token = profile.get('oauth_token')
                access_token_secret = profile.get('oauth_token_secret')
                user = _temp_reverse_user(uid, 'twitter', access_token, access_token_secret, payload)
            else:
                oauth = OAuth1(settings.SOCIAL_AUTH_TWITTER_KEY,
                               client_secret=settings.SOCIAL_AUTH_TWITTER_SECRET,
                               callback_uri=settings.TWITTER_CALLBACK_URL)
                r = requests.post(request_token_url, auth=oauth)
                access_token = dict(parse_qsl(r.text))
                return Response(access_token)

        elif backend in ['facebook']:
            access_token_url = 'https://graph.facebook.com/v2.3/oauth/access_token'
            graph_api_url = 'https://graph.facebook.com/v2.3/me'
            access_token = ""
            access_token_secret = ""
            params = {
                'client_id': request.data.get('clientId'),
                'redirect_uri': request.data.get('redirectUri'),
                'client_secret': settings.SOCIAL_AUTH_FACEBOOK_SECRET,
                'code': request.data.get('code')
            }

            # Step 1. Exchange authorization code for access token.
            r = requests.get(access_token_url, params=params)
            token = json.loads(r.text)

            # Step 2. Retrieve information about the current user.
            r = requests.get(graph_api_url, params=token)
            profile = json.loads(r.text)
            access_token = token.get('access_token')
            uid = profile.get('id')
            user = _temp_reverse_user(uid, 'facebook', access_token, access_token_secret, r.text)
        elif backend in ['google']:
            access_token_url = 'https://accounts.google.com/o/oauth2/token'
            people_api_url = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect'
            access_token = ""
            access_token_secret = ""
            payload = dict(client_id=request.data.get('clientId'),
                           redirect_uri=request.data.get('redirectUri'),
                           client_secret=settings.SOCIAL_AUTH_GOOGLE_OAUTH_SECRET,
                           code=request.data.get('code'),
                           grant_type='authorization_code')

            # Step 1. Exchange authorization code for access token.
            r = requests.post(access_token_url, data=payload)
            token = json.loads(r.text)
            headers = {'Authorization': 'Bearer {0}'.format(token['access_token'])}

            # Step 2. Retrieve information about the current user.
            r = requests.get(people_api_url, headers=headers)
            profile = json.loads(r.text)
            uid = profile.get('sub')
            user = _temp_reverse_user(uid, 'google', access_token, access_token_secret, r.text)

        if uid is not None and user is not None:
            if not user.user.is_active:
                return Response({
                    'status': 'Unauthorized',
                    'message': 'User account disabled'
                }, status=status.HTTP_401_UNAUTHORIZED)

            payload = jwt_payload_handler(user.user)
            if api_settings.JWT_ALLOW_REFRESH:
                payload['orig_iat'] = timegm(
                    datetime.datetime.utcnow().utctimetuple()
                )

            response_data = {
                'token': jwt_encode_handler(payload),
                'session': user.get_session_id()
            }

            return Response(response_data)

        return Response({
            'status': 'Bad request',
            'message': 'Authentication could not be performed with received data.'
        }, status=status.HTTP_400_BAD_REQUEST)


class ObtainUser(APIView):
    throttle_classes = ()
    permission_classes = ()
    parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
    renderer_classes = (renderers.JSONRenderer,)
    serializer_class = AuthTokenSerializer
    model = Token

    def post(self, request):
        return self.get(request)

    def get(self, request):
        if request.user.is_authenticated():
            return Response(
                status=status.HTTP_200_OK, data={
                    'id': request.user.id,
                    'name': request.user.username,
                    'session': request.user.userprofile.get_session_id(),
                    'slug': request.user.userprofile.slug,
                    'session': request.user.userprofile.get_session_id(),
                    'userRole': 'user',
                })
        else:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

[((1090, 1134), 'spa.models.socialaccountlink.SocialAccountLink.objects.get', 'SocialAccountLink.objects.get', ([], {'social_id': 'uid'}), '(social_id=uid)\n', (1119, 1134), False, 'from spa.models.socialaccountlink import SocialAccountLink\n'), ((1349, 1387), 'spa.models.UserProfile.objects.get', 'UserProfile.objects.get', ([], {'id': 'sa.user.id'}), '(id=sa.user.id)\n', (1372, 1387), False, 'from spa.models import UserProfile\n'), ((6887, 7039), 'rest_framework.response.Response', 'Response', (["{'status': 'Bad request', 'message':\n    'Authentication could not be performed with received data.'}"], {'status': 'status.HTTP_400_BAD_REQUEST'}), "({'status': 'Bad request', 'message':\n    'Authentication could not be performed with received data.'}, status=\n    status.HTTP_400_BAD_REQUEST)\n", (6895, 7039), False, 'from rest_framework.response import Response\n'), ((6475, 6505), 'rest_framework_jwt.utils.jwt_payload_handler', 'jwt_payload_handler', (['user.user'], {}), '(user.user)\n', (6494, 6505), False, 'from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler\n'), ((6847, 6870), 'rest_framework.response.Response', 'Response', (['response_data'], {}), '(response_data)\n', (6855, 6870), False, 'from rest_framework.response import Response\n'), ((7954, 7999), 'rest_framework.response.Response', 'Response', ([], {'status': 'status.HTTP_401_UNAUTHORIZED'}), '(status=status.HTTP_401_UNAUTHORIZED)\n', (7962, 7999), False, 'from rest_framework.response import Response\n'), ((1483, 1526), 'allauth.socialaccount.models.SocialAccount.objects.get', 'aamodels.SocialAccount.objects.get', ([], {'uid': 'uid'}), '(uid=uid)\n', (1517, 1526), True, 'from allauth.socialaccount import models as aamodels\n'), ((1788, 1807), 'spa.models.socialaccountlink.SocialAccountLink', 'SocialAccountLink', ([], {}), '()\n', (1805, 1807), False, 'from spa.models.socialaccountlink import SocialAccountLink\n'), ((3121, 3163), 'requests.post', 'requests.post', (['access_token_url'], {'auth': 'auth'}), '(access_token_url, auth=auth)\n', (3134, 3163), False, 'import requests\n'), ((3240, 3259), 'json.dumps', 'json.dumps', (['profile'], {}), '(profile)\n', (3250, 3259), False, 'import json\n'), ((3579, 3719), 'requests_oauthlib.OAuth1', 'OAuth1', (['settings.SOCIAL_AUTH_TWITTER_KEY'], {'client_secret': 'settings.SOCIAL_AUTH_TWITTER_SECRET', 'callback_uri': 'settings.TWITTER_CALLBACK_URL'}), '(settings.SOCIAL_AUTH_TWITTER_KEY, client_secret=settings.\n    SOCIAL_AUTH_TWITTER_SECRET, callback_uri=settings.TWITTER_CALLBACK_URL)\n', (3585, 3719), False, 'from requests_oauthlib import OAuth1\n'), ((3797, 3841), 'requests.post', 'requests.post', (['request_token_url'], {'auth': 'oauth'}), '(request_token_url, auth=oauth)\n', (3810, 3841), False, 'import requests\n'), ((3920, 3942), 'rest_framework.response.Response', 'Response', (['access_token'], {}), '(access_token)\n', (3928, 3942), False, 'from rest_framework.response import Response\n'), ((4564, 4609), 'requests.get', 'requests.get', (['access_token_url'], {'params': 'params'}), '(access_token_url, params=params)\n', (4576, 4609), False, 'import requests\n'), ((4630, 4648), 'json.loads', 'json.loads', (['r.text'], {}), '(r.text)\n', (4640, 4648), False, 'import json\n'), ((4733, 4774), 'requests.get', 'requests.get', (['graph_api_url'], {'params': 'token'}), '(graph_api_url, params=token)\n', (4745, 4774), False, 'import requests\n'), ((4797, 4815), 'json.loads', 'json.loads', (['r.text'], {}), '(r.text)\n', (4807, 4815), False, 'import json\n'), ((6284, 6397), 'rest_framework.response.Response', 'Response', (["{'status': 'Unauthorized', 'message': 'User account disabled'}"], {'status': 'status.HTTP_401_UNAUTHORIZED'}), "({'status': 'Unauthorized', 'message': 'User account disabled'},\n    status=status.HTTP_401_UNAUTHORIZED)\n", (6292, 6397), False, 'from rest_framework.response import Response\n'), ((6735, 6762), 'rest_framework_jwt.utils.jwt_encode_handler', 'jwt_encode_handler', (['payload'], {}), '(payload)\n', (6753, 6762), False, 'from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler\n'), ((1567, 1611), 'spa.models.UserProfile.objects.get', 'UserProfile.objects.get', ([], {'user__id': 'aa.user_id'}), '(user__id=aa.user_id)\n', (1590, 1611), False, 'from spa.models import UserProfile\n'), ((3195, 3212), 'urllib.parse.parse_qsl', 'parse_qsl', (['r.text'], {}), '(r.text)\n', (3204, 3212), False, 'from urllib.parse import parse_qsl\n'), ((3878, 3895), 'urllib.parse.parse_qsl', 'parse_qsl', (['r.text'], {}), '(r.text)\n', (3887, 3895), False, 'from urllib.parse import parse_qsl\n'), ((5698, 5743), 'requests.post', 'requests.post', (['access_token_url'], {'data': 'payload'}), '(access_token_url, data=payload)\n', (5711, 5743), False, 'import requests\n'), ((5764, 5782), 'json.loads', 'json.loads', (['r.text'], {}), '(r.text)\n', (5774, 5782), False, 'import json\n'), ((5951, 5996), 'requests.get', 'requests.get', (['people_api_url'], {'headers': 'headers'}), '(people_api_url, headers=headers)\n', (5963, 5996), False, 'import requests\n'), ((6019, 6037), 'json.loads', 'json.loads', (['r.text'], {}), '(r.text)\n', (6029, 6037), False, 'import json\n'), ((6619, 6645), 'datetime.datetime.utcnow', 'datetime.datetime.utcnow', ([], {}), '()\n', (6643, 6645), False, 'import datetime\n')]