# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2016 Continuum Analytics, Inc.
#
# May be copied and distributed freely only as part of an Anaconda or
# Miniconda installation.
# -----------------------------------------------------------------------------
"""Preferences dialog."""

# Third party imports
from qtpy.QtCore import QRegExp, Qt, Signal
from qtpy.QtGui import QPixmap, QRegExpValidator
from qtpy.QtWidgets import (QCheckBox, QGridLayout, QHBoxLayout, QLabel,
                            QLineEdit, QVBoxLayout, QWidget)

# Local imports
from anaconda_navigator.api.anaconda_api import AnacondaAPI
from anaconda_navigator.config import CONF
from anaconda_navigator.static.images import WARNING_ICON
from anaconda_navigator.widgets import (ButtonNormal, ButtonPrimary,
                                        SpacerHorizontal, SpacerVertical)
from anaconda_navigator.widgets.dialogs import DialogBase


class PreferencesDialog(DialogBase):
    """Application preferences dialog."""

    sig_urls_updated = Signal(str, str)

    def __init__(self, config=CONF, **kwargs):
        """Application preferences dialog."""
        super(PreferencesDialog, self).__init__(**kwargs)

        self.api = AnacondaAPI()
        self.widgets_changed = set()
        self.widgets = []
        self.config = CONF

        # Widgets
        self.button_ok = ButtonPrimary('Apply')
        self.button_cancel = ButtonNormal('Cancel')
        self.button_reset = ButtonNormal('Reset to defaults')
        self.row = 0

        # Widget setup
        self.setWindowTitle("Preferences")

        # Layouts
        self.grid_layout = QGridLayout()

        buttons_layout = QHBoxLayout()
        buttons_layout.addWidget(self.button_reset)
        buttons_layout.addStretch()
        buttons_layout.addWidget(self.button_cancel)
        buttons_layout.addWidget(SpacerHorizontal())
        buttons_layout.addWidget(self.button_ok)

        main_layout = QVBoxLayout()
        main_layout.addLayout(self.grid_layout)
        main_layout.addWidget(SpacerVertical())
        main_layout.addWidget(SpacerVertical())
        main_layout.addLayout(buttons_layout)
        self.setLayout(main_layout)

        # Signals
        self.button_ok.clicked.connect(self.accept)
        self.button_cancel.clicked.connect(self.reject)
        self.button_reset.clicked.connect(self.reset_to_defaults)
        self.button_reset.clicked.connect(
            lambda: self.button_ok.setEnabled(True))

        # Setup
        self.grid_layout.setSpacing(0)
        self.setup()
        self.button_ok.setDisabled(True)
        self.widgets[0].setFocus()
        self.button_ok.setDefault(True)
        self.button_ok.setAutoDefault(True)

    # --- Helpers
    # -------------------------------------------------------------------------
    def get_option(self, option):
        """Get configuration option from `main` section."""
        return self.config.get('main', option, None)

    def set_option(self, option, value, default=False):
        """Set configuration option in `main` section."""
        self.config.set('main', option, value)

    def set_option_default(self, option):
        """Set configuration option default value in `main` section."""
        default = self.config.get_default('main', option)
        self.set_option(option, default)

    def create_widget(self,
                      widget=None,
                      label=None,
                      option=None,
                      hint=None,
                      check=None):
        """Create preference option widget and add to layout."""
        if hint:
            widget.setPlaceholderText(hint)

        config_value = self.get_option(option)
        widget.label = QLabel(label)
        widget.option = option
        widget.set_value(config_value)
        widget.label_information = QLabel()
        widget.label_information.setMinimumWidth(20)
        widget.label_information.setMaximumWidth(20)

        form_widget = QWidget()
        h_layout = QHBoxLayout()
        h_layout.addSpacing(4)
        h_layout.addWidget(widget.label_information, 0, Qt.AlignRight)
        h_layout.addWidget(widget, 0, Qt.AlignLeft)
        form_widget.setLayout(h_layout)

        if check:
            widget.check_value = lambda value: check(value)
        else:
            widget.check_value = lambda value: (True, '')

        self.widgets.append(widget)
        self.grid_layout.addWidget(widget.label, self.row, 0,
                                   Qt.AlignRight | Qt.AlignCenter)
        self.grid_layout.addWidget(form_widget, self.row, 1,
                                   Qt.AlignLeft | Qt.AlignCenter)
        self.row += 1

    def create_textbox(self,
                       label,
                       option,
                       hint=None,
                       regex=None,
                       check=None):
        """Create textbox (QLineEdit) preference option."""
        widget = QLineEdit()
        widget.setAttribute(Qt.WA_MacShowFocusRect, False)
        widget.setMinimumWidth(250)

        if regex:
            regex_validator = QRegExpValidator(QRegExp(regex))
            widget.setValidator(regex_validator)

        widget.get_value = lambda w=widget: w.text()
        widget.set_value = lambda value, w=widget: w.setText(value)
        widget.set_warning = lambda w=widget: w.setSelection(0, 1000)
        widget.textChanged.connect(
            lambda v=None, w=widget: self.options_changed(widget=w))

        self.create_widget(widget=widget, option=option, label=label,
                           hint=hint, check=check)

    def create_checkbox(self, label, option, hint=None):
        """Create checkbox preference option."""
        widget = QCheckBox()
        widget.get_value = lambda w=widget: bool(w.checkState())
        widget.set_value = lambda value, w=widget: bool(
            w.setCheckState(Qt.Checked if value else Qt.Unchecked))
        widget.stateChanged.connect(
            lambda v=None, w=widget: self.options_changed(widget=w))
        self.create_widget(widget=widget, option=option, label=label,
                           hint=hint)

    def options_changed(self, value=None, widget=None):
        """Callback helper triggred on preference value change."""
        config_value = self.get_option(widget.option)

        if config_value != widget.get_value():
            self.widgets_changed.add(widget)
        else:
            if widget in self.widgets_changed:
                self.widgets_changed.remove(widget)

        self.button_ok.setDisabled(not bool(len(self.widgets_changed)))

    # --- API
    # -------------------------------------------------------------------------
    def setup(self):
        """Setup the preferences dialog."""
        self.config.set('main', 'anaconda_api_url',
                        self.api.client_get_api_url())
        self.create_textbox('Anaconda API domain', 'anaconda_api_url',
                            check=self.is_valid_api)
#        self.create_textbox('Conda domain', 'conda_url',
#                            check=self.is_valid_url)
        self.create_checkbox('Provide analytics', 'provide_analytics')
        self.create_checkbox('Hide quit dialog', 'hide_quit_dialog')
        self.create_checkbox('Enable high DPI scaling',
                             'enable_high_dpi_scaling')

    @staticmethod
    def warn(widget, text=None):
        """Display warning for widget in preferences."""
        label = widget.label_information
        if text:
            pixmap = QPixmap(WARNING_ICON)
            label.setPixmap(pixmap.scaled(16, 16, Qt.KeepAspectRatio,
                                          Qt.SmoothTransformation))
            label.setToolTip(str(text))
        else:
            label.setPixmap(QPixmap())
            label.setToolTip('')

    # --- Checkers
    # -------------------------------------------------------------------------
    def is_valid_url(self, url):
        """Check if a given URL returns a 200 code."""
        output = self.api.download_is_valid_url(url, non_blocking=False)
        error = ''
        if not output:
            error = 'Invalid url'
        return output, error

    def is_valid_api(self, url):
        """Check if a given URL is a valid anaconda api endpoint."""
        output = self.api.download_is_valid_api_url(url, non_blocking=False)
        error = ''
        if not output:
            error = 'Invalid Anaconda API url.'
        return output, error

    def reset_to_defaults(self):
        """Reset the preferences to the default values."""
        # ASK!
        for widget in self.widgets:
            option = widget.option
            self.set_option_default(option)
            value = self.get_option(option)
            widget.set_value(value)

            # Special case for anaconda api
            if option == 'anaconda_api_url':
                self.set_option(option=option, value='')

            # Flag all values as updated
            self.options_changed(widget=widget, value=value)

    def accept(self):
        """Qt override."""
        sig_updated = False
        for widget in self.widgets_changed:
            option = widget.option
            value = widget.get_value()
            check, error = widget.check_value(value)

            if check:
                self.set_option(option, value)
                self.warn(widget)
            else:
                self.button_ok.setDisabled(True)
                widget.set_warning()
                self.warn(widget, error)
                return

            if widget.option == 'anaconda_api_url':
                self.api.client_set_api_url(value)
                sig_updated = True

        for widget in self.widgets:
            if widget.option == 'anaconda_api_url':
                anaconda_api_url = widget.get_value()

        if sig_updated:
            conda_url = self.api.download_get_api_info()['conda_url']
            self.sig_urls_updated.emit(anaconda_api_url, conda_url)

        super(PreferencesDialog, self).accept()


# --- Local testing
# -----------------------------------------------------------------------------
def test():  # pragma: no cover
    """Main local testing."""
    from anaconda_navigator.utils.qthelpers import qapplication
    app = qapplication()
    widget = PreferencesDialog(parent=None)
    widget.show()
    app.exec_()


if __name__ == '__main__':  # pragma: no cover
    test()
