# -*- coding: utf-8 -*-
#
# This file is part of the shibboleth-authenticator module for Invenio.
# Copyright (C) 2017  Helmholtz-Zentrum Dresden-Rossendorf
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""Handlers for shibboleth endpoints."""

from __future__ import absolute_import, print_function

from flask import current_app, redirect, session
from flask_login import current_user
from invenio_db import db
from invenio_oauthclient.handlers import (get_session_next_url,
                                          oauth_error_handler,
                                          token_session_key)
from invenio_oauthclient.utils import (create_csrf_disabled_registrationform,
                                       fill_form, oauth_authenticate,
                                       oauth_get_user, oauth_register)
from werkzeug.local import LocalProxy

from .utils import get_account_info

_security = LocalProxy(lambda: current_app.extensions['security'])

_datastore = LocalProxy(lambda: _security.datastore)


#
# Handlers
#
@oauth_error_handler
def authorized_signup_handler(auth, remote=None, *args, **kwargs):
    """
    Handle sign-in/up functionality.

    Checks if user is already registered. If not registered, the function
    registers a new user and authenticates the new user. If there already
    exists a user object in the database, the user is only authenticated and
    logged in.

    :param remote: The remote application.
    :param resp: The response.
    :returns: Redirect response.
    """
    # Remove any previously stored auto register session key
    session.pop(token_session_key(remote) + '_autoregister', None)

    # Sign-in/up user
    # ---------------
    if not current_user.is_authenticated:
        account_info = get_account_info(auth.get_attributes(), remote)

        user = oauth_get_user(
            remote,
            account_info=account_info
        )
        if user is None:
            # Auto sign-up if user not found
            form = create_csrf_disabled_registrationform()
            form = fill_form(
                form,
                account_info['user']
            )

            user = oauth_register(form)

            # if registration fails ...
            if user is None:
                return current_app.login_manager.unauthorized()

        # Authenticate user
        if not oauth_authenticate(remote, user,
                                  require_existing_link=False):
            return current_app.login_manager.unauthorized()

    db.session.commit()

    # Redirect to next
    next_url = get_session_next_url(remote)
    if next_url:
        return redirect(next_url)
    return redirect(current_app.config['SECURITY_POST_LOGIN_VIEW'])
