from urllib.parse import urlencode
from uuid import uuid4
import logging

from django.shortcuts import redirect, render
from django.conf import settings
from django.urls import reverse
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseBadRequest
from django.utils.dateparse import parse_datetime

import withings.api
import withings.models
import gotify.api
import gotify.models
from medwings.forms import ProfileForm
from .forms import CustomUserCreationForm


def register_init(request):
    if request.user.is_authenticated:
        raise PermissionDenied('You are already registered and logged in.')

    # Generate a unique token and save it for later
    request.session.flush()
    registration_sequence_token = str(uuid4())
    request.session['registration_sequence_token'] = registration_sequence_token

    auth_url_base = 'https://account.withings.com/oauth2_user/authorize2'
    auth_url_params = {
        'response_type': 'code',
        'client_id': settings.WITHINGS_CONFIG['CLIENT_ID'],
        'scope': 'user.metrics,user.activity',
        'redirect_uri': request.build_absolute_uri(reverse('register-continue')),
        'state': registration_sequence_token
    }
    auth_url = f"{auth_url_base}?{urlencode(auth_url_params)}"

    context = {
        "auth_url": auth_url
    }

    return render(request, 'authentication/register-init.html', context)


def register_continue(request):
    if request.user.is_authenticated:
        raise PermissionDenied('You are already registered and logged in.')

    authorization_code = request.GET.get('code')
    authorization_state = request.GET.get('state')
    if not authorization_code:
        return HttpResponseBadRequest()
    if not authorization_state:
        return HttpResponseBadRequest()
    if not request.session.get('registration_sequence_token', None) == authorization_state:
        return HttpResponseBadRequest()

    if request.method == 'GET':
        # Fetch access and refresh tokens and save them to session storage
        redirect_uri = request.build_absolute_uri(reverse('register-continue'))
        response_data = withings.api.fetch_initial_tokens(authorization_code, redirect_uri)
        if response_data['status'] != 0:
            return HttpResponseBadRequest()
        withings.api.save_tokens_to_session(request, response_data)

        user_form = CustomUserCreationForm()
        profile_form = ProfileForm()

    else:
        user_form = CustomUserCreationForm(request.POST)
        profile_form = ProfileForm(request.POST)

        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save(commit=False)
            profile = profile_form.save(commit=False)
            profile.user = user

            user_password = request.POST.get('password1')
            gotify_user_info = gotify.api.create_user(user.username, user_password)
            gotify_app_info = gotify.api.create_application(user.username, user_password)
            gotify.api.upload_application_picture(user.username, user_password, gotify_app_info['id'])
            gotify_user = gotify.models.GotifyUser(
                user=user,
                id=gotify_user_info['id']
            )
            gotify_app = gotify.models.GotifyApplication(
                user=gotify_user,
                id=gotify_app_info['id'],
                token=gotify_app_info['token']
            )

            withings_api_account = withings.models.ApiAccount(
                user=user,
                userid=request.session.get('withings_userid')
            )
            withings_access_token = withings.models.AccessToken(
                account=withings_api_account,
                value=request.session.get('withings_access_token'),
                expires=parse_datetime(request.session.get('withings_access_token_expiry'))
            )
            withings_refresh_token = withings.models.RefreshToken(
                account=withings_api_account,
                value=request.session.get('withings_refresh_token'),
                expires=parse_datetime(request.session.get('withings_refresh_token_expiry'))
            )

            for instance in [
                user, profile,
                gotify_user, gotify_app,
                withings_api_account, withings_access_token, withings_refresh_token
            ]:
                instance.save()

            request.session.flush()
            withings_api_account.update_records()

            return redirect('register-finalize')

    context = {
        'user_form': user_form,
        'profile_form': profile_form,
    }

    return render(request, 'authentication/register-continue.html', context)


def register_finalize(request):
    if request.user.is_authenticated:
        raise PermissionDenied('You are already registered and logged in.')

    context = {
        "gotify_public_url": settings.GOTIFY_CONFIG['PUBLIC_URL']
    }

    return render(request, 'authentication/register-finalize.html', context)
