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

# -----------------------------------------------------------------------------
# Copyright (c) 2016-2017 Anaconda, Inc.
#
# May be copied and distributed freely only as part of an Anaconda or
# Miniconda installation.
# -----------------------------------------------------------------------------

"""Anaconda Cloud login dialogs."""

__all__ = ['CloudLoginPage']

import typing
import requests
from qtpy.QtCore import Qt
from qtpy.QtWidgets import QApplication, QWidget  # pylint: disable=no-name-in-module
from anaconda_navigator.api import cloud as cloud_api
from anaconda_navigator.config import CONF, AnacondaBrand
from anaconda_navigator.static.images import ANACONDA_CLOUD_LOGIN_LOGO
from anaconda_navigator.utils import attribution
from anaconda_navigator.utils import url_utils
from anaconda_navigator.utils import workers
from .base_dialogs import BaseLoginPage
from . import utils

CLOUD_LOGIN_TEXT_CONTAINER = utils.TextContainer(
    title='Sign In',
    info_frame_text=(
        utils.Span(
            'Log into Anaconda Cloud to backup your environment and access '  # pylint: disable=implicit-str-concat
            'more data science tools. If you don’t have an account, click '
            '<a href="{}" style="color:#43B049;text-decoration: none">here</a>.'
        ),
    ),
    form_forgot_links_msg=(
        'Forget your <a href="{password_url}" style="color:#43B049; text-decoration:none">password</a>?'
    ),
    message_box_error_text='The Anaconda Cloud API domain is not specified! Please, set in preferences.',
    header_frame_logo_path=ANACONDA_CLOUD_LOGIN_LOGO,
)


class CloudLoginPage(BaseLoginPage):  # pylint: disable=missing-class-docstring

    def __init__(self, parent: typing.Optional[QWidget] = None) -> None:
        """Initialize new :class:`~CloudLoginPage` instance."""
        super().__init__(cloud_api.CloudAPI(), CLOUD_LOGIN_TEXT_CONTAINER, parent=parent)
        self.api_url_config_option = 'cloud_base_url'
        self.brand = AnacondaBrand.CLOUD

        self.label_login.setText('Email')
        self.text_login.setValidator(utils.EMAIL_RE_VALIDATOR)

        self.finished.connect(self.__finished)

    def login(self):
        base_url = CONF.get('main', self.api_url_config_option)
        if not base_url:
            self._show_message_box(title='Login Error', text=self.text_container.domain_not_found_msg)
            return

        self.button_login.setEnabled(False)
        QApplication.setOverrideCursor(Qt.WaitCursor)

        self.label_message.setText('')
        self.label_message.setVisible(False)

        text_login: str = self.text_login.text().lower()
        self.text_login.setText(text_login)

        worker: workers.TaskWorker = self.api.login.worker(
            username=text_login,
            password=self.text_password.text(),
        )
        self.finished.connect(worker.cancel)
        worker.signals.sig_done.connect(lambda result: self.finished.disconnect(worker.cancel))
        worker.signals.sig_done.connect(self.__process_login_response)
        worker.start()

    def __process_login_response(self, result: workers.TaskResult) -> None:
        """Check response from Cloud server for login."""
        if not self.isVisible():
            return

        self.button_login.setDisabled(False)
        self.check_text()
        QApplication.restoreOverrideCursor()

        error_msg: typing.Optional[str] = None
        if result.status != workers.TaskStatus.SUCCEEDED:
            error: BaseException = typing.cast(BaseException, result.exception)
            error_msg = str(error)
            if isinstance(error, requests.RequestException) and (error.response is not None):
                if error.response.status_code in (401, 403):
                    error_msg = 'Invalid credentials'

        if self.api.token.valid:
            self.accept()
            return

        if error_msg is not None:
            self.label_message.setText(error_msg)
            self.label_message.setVisible(True)

            url: str = CONF.get('main', self.api_url_config_option, '-')
            username: str = result.call.kwargs['username']
            self.tracker.track_event('authenticate', 'login failed', label=f'{url}/{username}: {error_msg.lower()}')

            self.text_password.setFocus()
            self.text_password.selectAll()

    @staticmethod
    def __finished() -> None:
        """Update dialog state when it is closed."""
        QApplication.restoreOverrideCursor()

    def update_links(self):
        """Update links."""
        base_url = CONF.get('main', 'cloud_base_url', None)

        if not base_url:
            return

        base_url = base_url.rstrip('/')  # pylint: disable=no-member
        forgot_url = attribution.POOL.settings.inject_url_parameters(
            url_utils.join(base_url, 'forgot-password'),
            utm_medium='connect-cloud',
            utm_content='password-reset',
        )
        sign_up_url = attribution.POOL.settings.inject_url_parameters(
            url_utils.join(base_url, 'sign-up'),
            utm_medium='connect-cloud',
            utm_content='signup',
        )

        forgot_links_updated_text = self.forgot_links.text().format(password_url=forgot_url)
        info_updated_text = self.label_information.text().format(sign_up_url)

        self.label_information.setText(info_updated_text)
        self.forgot_links.setText(forgot_links_updated_text)

        self.label_information.linkActivated.connect(self.open_url)
        self.forgot_links.linkActivated.connect(self.open_url)
