# coding: utf-8

import os
import re
import secrets

from django.conf import settings
from django.core.cache import cache
from django.http import HttpResponse, HttpResponseRedirect
from django.template.loader import get_template
from django.utils.html import escape
from django.utils.translation import get_language, gettext_lazy as _
from yarl import URL

from procu.api import models
from procu.api.csp import get_csp_header
from procu.api.saving.utils import get_total_saving
from procu.api.utils import (
    get_current_url,
    get_front_version,
    is_internal,
    json_dumps,
    timed_access_logger,
)

RE_METRICA = re.compile(r'^https?://([^/]+\.)?webvisor\.com/')


PASSPORTS = {
    'create': URL('https://passport.yandex-team.ru/auth/secure/'),
    'resign': URL('https://pass.yandex-team.ru/resign'),
}

NO_REPEAT_MARK = '_yauth'

html_template = get_template('main.html')
react_template = get_template('react.html')

# ------------------------------------------------------------------------------


def maybe_remove_url_params(request):

    ref_param = settings.URL_PARAM_REF

    try:
        (email,) = models.QuoteRef.objects.values_list('user__email').get(
            ref=request.GET[ref_param]
        )
        request.session[settings.SESSION_KEY_EMAIL] = email

        url = get_current_url(request, del_params=[ref_param])
        return HttpResponseRedirect(url)

    except (models.QuoteRef.DoesNotExist, KeyError):
        pass

    if settings.URL_PARAM_AUTH in request.GET:
        url = get_current_url(request, del_params=[settings.URL_PARAM_AUTH])
        return HttpResponseRedirect(url)


def maybe_redirect_to_resign(request):

    if request.yauser and request.yauser.need_reset:
        retpath = get_current_url(request)
        url = PASSPORTS['resign'].with_query(retpath=retpath)

        response = HttpResponseRedirect(str(url))
        response.set_cookie(
            settings.YAUTH_COOKIE_CHECK_COOKIE_NAME,
            'Cookie_check',
            None,
            None,
            '/',
            '.yandex-team.ru',
            secure=settings.SESSION_COOKIE_SECURE,
            httponly=settings.SESSION_COOKIE_HTTPONLY,
        )

        return response


# ------------------------------------------------------------------------------


def maybe_redirect_to_passport(request, prefix=''):

    if request.user.is_authenticated:
        return

    if NO_REPEAT_MARK in request.GET:
        page_data = {
            'error': {'status': 401, 'message': 'Could not authenticate'}
        }

        return get_response(request, prefix, page_data)

    retpath = get_current_url(request)
    url = PASSPORTS['create'].with_query(retpath=retpath, **{NO_REPEAT_MARK: 1})
    return HttpResponseRedirect(str(url))


def maybe_redirect_to_login(request, prefix=''):

    if request.user.is_authenticated:
        return

    path_suffix = request.path.rpartition('/')[-1]

    if path_suffix not in ('login', 'reset'):

        current_url = get_current_url(request)
        retpath = URL(current_url)

        login_url = retpath.with_path(f'{prefix}/login').with_query(
            retpath=str(retpath)
        )

        return HttpResponseRedirect(str(login_url))


# ------------------------------------------------------------------------------


def get_user_language(request):

    language = get_language()

    user = request.user

    if user.is_authenticated and not settings.IS_PRODUCTION:
        if user.is_staff:
            assert request.yauser
            if user.language:
                language = user.language
            else:
                language = request.yauser.language
        else:
            language = user.language

        if language not in dict(settings.LANGUAGES):
            language = settings.LANGUAGE_CODE

    return language


def get_response(request, prefix, page_data=None, template=None):

    page_data = page_data or {}
    page_data['user'] = {}

    user = request.user

    if user.is_authenticated:
        page_data['user'].update(
            {
                'id': user.id,
                'username': escape(user.username),
                'full_name': escape(user.full_name),
            }
        )

    lang = get_user_language(request)
    page_data['user']['lang'] = lang

    csp = get_csp_header(request)

    if prefix:
        front_random = secrets.token_hex(16)
        static_prefix = ''

    else:
        front_random = get_front_version()
        qloud_env = os.getenv('YENV_ENVIRONMENT', '')
        yastatic_domain = 'yastatic.net' if qloud_env == 'production' else 'l7test.yastatic.net'
        static_prefix = f'//{yastatic_domain}/q/procu-{qloud_env}'

    if is_internal(request):
        counter_id = settings.COUNTER_ID_INT
    else:
        counter_id = settings.COUNTER_ID_EXT

    context = {
        'front_version': front_random,
        'lang': lang,
        'static_prefix': static_prefix,
        'user_type': 'internal' if is_internal(request) else 'external',
        'csp_nonce': csp.nonce,
        'user': json_dumps(page_data),
        'counter': counter_id,
        'is_production': settings.IS_PRODUCTION,
    }

    if template is None:
        if request.META.get('HTTP_X_REACT') is not None:
            template = react_template
        else:
            template = html_template

    response = HttpResponse(template.render(context=context))

    # --------------------------------------------------------------
    # CSP

    response['Content-Security-Policy'] = csp.header

    if not RE_METRICA.match(request.META.get('HTTP_REFERER', '')):
        response['X-Frame-Options'] = 'DENY'

    response['X-Content-Type-Options'] = 'nosniff'
    response['X-XSS-Protection'] = '1; mode=block'

    return response


# ------------------------------------------------------------------------------


def main_internal(request, prefix, template=None):

    user = request.user

    # Instantiate lazy user-object
    is_authenticated = user.is_authenticated

    if is_authenticated:
        response = maybe_redirect_to_resign(request)
        if response is not None:
            return response

    else:
        response = maybe_redirect_to_passport(request, prefix)
        if response is not None:
            return response

    if not user.has_perm('api.retrieve_enquiry') or 'noaccess' in request.GET:
        page_data = {
            'error': {
                'status': '403',
                'data': {
                    'error_title': _('ERRORS::PROCU_PERMISSION_DENIED'),
                    'error_code': 'PROCU_PERMISSION_DENIED',
                    'detail': _('ERRORS::PROCU_PERMISSION_DENIED'),
                },
            }
        }
        return get_response(request, prefix, page_data)

    page_data = {'env': 'production' if settings.IS_PRODUCTION else 'testing'}

    if user.has_perm('api.progress_enquiry'):
        page_data['saving'] = cache.get_or_set(
            'total_saving', get_total_saving, timeout=3600 * 2
        )

    image = os.getenv('DEPLOY_DOCKER_IMAGE', ':')
    version = image.split(':')[1]

    page_data['version'] = version

    return get_response(request, prefix, page_data, template)


def main_external(request, prefix):

    user = request.user

    # Instantiate lazy user-object
    is_authenticated = user.is_authenticated

    response = maybe_remove_url_params(request)
    if response is not None:
        return response

    if not is_authenticated:
        response = maybe_redirect_to_login(request, prefix)
        if response is not None:
            return response

    return get_response(request, prefix)


@timed_access_logger
def main(request, prefix=''):
    if is_internal(request):
        return main_internal(request, prefix)
    else:
        return main_external(request, prefix)


@timed_access_logger
def products(request, prefix=''):
    return main_internal(request, prefix, react_template)
