# -*- coding: utf-8 -*-

# Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import datetime
import logging
import uuid

import pyramid.security as security

from pyramid.view import view_config
from pyramid.httpexceptions import HTTPFound
from pyramid.response import Response
from pyramid.security import NO_PERMISSION_REQUIRED
from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInSuccess
from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInBadAuth
from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignOut
from ziggurat_foundations.models.services.user import UserService

from appenlight.lib.social import handle_social_data
from appenlight.models import DBSession
from appenlight.models.user import User
from appenlight.models.services.user import UserService
from appenlight.subscribers import _
from appenlight import forms
from webob.multidict import MultiDict

log = logging.getLogger(__name__)


@view_config(context=ZigguratSignInSuccess, permission=NO_PERMISSION_REQUIRED)
def sign_in(request):
    """
    Performs sign in by sending proper user identification headers
    Regenerates CSRF token
    """
    user = request.context.user
    if user.status == 1:
        request.session.new_csrf_token()
        user.last_login_date = datetime.datetime.utcnow()
        social_data = request.session.get("zigg.social_auth")
        if social_data:
            handle_social_data(request, user, social_data)
    else:
        request.session.flash(_("Account got disabled"))

    if request.context.came_from != "/":
        return HTTPFound(
            location=request.context.came_from, headers=request.context.headers
        )
    else:
        return HTTPFound(
            location=request.route_url("/"), headers=request.context.headers
        )


@view_config(context=ZigguratSignInBadAuth, permission=NO_PERMISSION_REQUIRED)
def bad_auth(request):
    """
    Handles incorrect login flow
    """
    request.session.flash(_("Incorrect username or password"), "warning")
    return HTTPFound(
        location=request.route_url("register"), headers=request.context.headers
    )


@view_config(context=ZigguratSignOut, permission=NO_PERMISSION_REQUIRED)
def sign_out(request):
    """
    Removes user identification cookie
    """
    return HTTPFound(
        location=request.route_url("register"), headers=request.context.headers
    )


@view_config(
    route_name="lost_password",
    renderer="appenlight:templates/user/lost_password.jinja2",
    permission=NO_PERMISSION_REQUIRED,
)
def lost_password(request):
    """
    Presents lost password page - sends password reset link to
    specified email address.
    This link is valid only for 10 minutes
    """
    form = forms.LostPasswordForm(request.POST, csrf_context=request)
    if request.method == "POST" and form.validate():
        user = UserService.by_email(form.email.data)
        if user:
            UserService.regenerate_security_code(user)
            user.security_code_date = datetime.datetime.utcnow()
            email_vars = {
                "user": user,
                "request": request,
                "email_title": "AppEnlight :: New password request",
            }
            UserService.send_email(
                request,
                recipients=[user.email],
                variables=email_vars,
                template="/email_templates/lost_password.jinja2",
            )
            msg = (
                "Password reset email had been sent. "
                "Please check your mailbox for further instructions."
            )
            request.session.flash(_(msg))
            return HTTPFound(location=request.route_url("lost_password"))
    return {"form": form}


@view_config(
    route_name="lost_password_generate",
    permission=NO_PERMISSION_REQUIRED,
    renderer="appenlight:templates/user/lost_password_generate.jinja2",
)
def lost_password_generate(request):
    """
    Shows new password form - perform time check and set new password for user
    """
    user = UserService.by_user_name_and_security_code(
        request.GET.get("user_name"), request.GET.get("security_code")
    )
    if user:
        delta = datetime.datetime.utcnow() - user.security_code_date

    if user and delta.total_seconds() < 600:
        form = forms.NewPasswordForm(request.POST, csrf_context=request)
        if request.method == "POST" and form.validate():
            UserService.set_password(user, form.new_password.data)
            request.session.flash(_("You can sign in with your new password."))
            return HTTPFound(location=request.route_url("register"))
        else:
            return {"form": form}
    else:
        return Response("Security code expired")


@view_config(
    route_name="register",
    renderer="appenlight:templates/user/register.jinja2",
    permission=NO_PERMISSION_REQUIRED,
)
def register(request):
    """
    Render register page with form
    Also handles oAuth flow for registration
    """
    login_url = request.route_url("ziggurat.routes.sign_in")
    if request.query_string:
        query_string = "?%s" % request.query_string
    else:
        query_string = ""
    referrer = "%s%s" % (request.path, query_string)

    if referrer in [login_url, "/register", "/register?sign_in=1"]:
        referrer = "/"  # never use the login form itself as came_from
    sign_in_form = forms.SignInForm(
        came_from=request.params.get("came_from", referrer), csrf_context=request
    )

    # populate form from oAuth session data returned by authomatic
    social_data = request.session.get("zigg.social_auth")
    if request.method != "POST" and social_data:
        log.debug(social_data)
        user_name = social_data["user"].get("user_name", "").split("@")[0]
        form_data = {"user_name": user_name, "email": social_data["user"].get("email")}
        form_data["user_password"] = str(uuid.uuid4())
        form = forms.UserRegisterForm(MultiDict(form_data), csrf_context=request)
        form.user_password.widget.hide_value = False
    else:
        form = forms.UserRegisterForm(request.POST, csrf_context=request)
    if request.method == "POST" and form.validate():
        log.info("registering user")
        # insert new user here
        if request.registry.settings["appenlight.disable_registration"]:
            request.session.flash(_("Registration is currently disabled."))
            return HTTPFound(location=request.route_url("/"))

        new_user = User()
        DBSession.add(new_user)
        form.populate_obj(new_user)
        UserService.regenerate_security_code(new_user)
        new_user.status = 1
        UserService.set_password(new_user, new_user.user_password)
        new_user.registration_ip = request.environ.get("REMOTE_ADDR")

        if social_data:
            handle_social_data(request, new_user, social_data)

        email_vars = {
            "user": new_user,
            "request": request,
            "email_title": "AppEnlight :: Start information",
        }
        UserService.send_email(
            request,
            recipients=[new_user.email],
            variables=email_vars,
            template="/email_templates/registered.jinja2",
        )
        request.session.flash(_("You have successfully registered."))
        DBSession.flush()
        headers = security.remember(request, new_user.id)
        return HTTPFound(location=request.route_url("/"), headers=headers)
    settings = request.registry.settings
    social_plugins = {}
    if settings.get("authomatic.pr.twitter.key", ""):
        social_plugins["twitter"] = True
    if settings.get("authomatic.pr.google.key", ""):
        social_plugins["google"] = True
    if settings.get("authomatic.pr.github.key", ""):
        social_plugins["github"] = True
    if settings.get("authomatic.pr.bitbucket.key", ""):
        social_plugins["bitbucket"] = True

    return {
        "form": form,
        "sign_in_form": sign_in_form,
        "social_plugins": social_plugins,
    }


@view_config(
    route_name="/",
    renderer="appenlight:templates/app.jinja2",
    permission=NO_PERMISSION_REQUIRED,
)
@view_config(
    route_name="angular_app_ui",
    renderer="appenlight:templates/app.jinja2",
    permission=NO_PERMISSION_REQUIRED,
)
@view_config(
    route_name="angular_app_ui_ix",
    renderer="appenlight:templates/app.jinja2",
    permission=NO_PERMISSION_REQUIRED,
)
def app_main_index(request):
    """
    Render dashoard/report browser page page along with:
     - flash messages
     - application list
     - assigned reports
     - latest events
     (those last two come from subscribers.py that sets global renderer variables)
    """
    return {}
