# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)

"""
Language server Status widget.
"""

# Standard library imports
import logging
import os

# Third party imports
from qtpy.QtCore import QPoint, Slot
from qtpy.QtWidgets import QMenu

# Local imports
from spyder.api.widgets.status import StatusBarWidget
from spyder.config.base import _
from spyder.utils.qthelpers import add_actions, create_action

logger = logging.getLogger(__name__)


# Main constants
class ClientStatus:
    STARTING = 'starting'
    READY = 'ready'
    RESTARTING = 'restarting'
    DOWN = 'down'

    STRINGS_FOR_TRANSLATION = {
        STARTING: _("starting"),
        READY: _("ready"),
        RESTARTING: _("restarting"),
        DOWN: _("down")
    }


class LSPStatusWidget(StatusBarWidget):
    """Status bar widget for LSP  status."""
    ID = 'lsp_status'

    BASE_TOOLTIP = _(
        "Completions, linting, code\n"
        "folding and symbols status."
    )

    STATUS = "LSP: {}"

    def __init__(self, parent, provider):
        self.tooltip = self.BASE_TOOLTIP
        super().__init__(parent, show_spinner=True)

        self.provider = provider
        self.current_language = None
        self.menu = QMenu(self)

        # Setup
        self.set_status(status=ClientStatus.STARTING)

        # Signals
        self.sig_clicked.connect(self.show_menu)

    def show_menu(self):
        """Display a menu when clicking on the widget."""
        menu = self.menu
        language = self.current_language.lower()

        if language is not None:
            menu.clear()
            text = _(
                "Restart {} Language Server").format(language.capitalize())
            restart_action = create_action(
                self,
                text=text,
                triggered=lambda: self.provider.restart_lsp(language,
                                                            force=True),
            )
            add_actions(menu, [restart_action])
            rect = self.contentsRect()
            os_height = 7 if os.name == 'nt' else 12
            pos = self.mapToGlobal(
                rect.topLeft() + QPoint(-40, -rect.height() - os_height))
            menu.popup(pos)

    def set_status(self, lsp_language=None, status=None):
        """Set LSP status."""
        # Spinner
        if status in [ClientStatus.STARTING, ClientStatus.RESTARTING]:
            self.spinner.show()
            self.spinner.start()
        else:
            self.spinner.hide()
            self.spinner.stop()

        # Icon
        if status == ClientStatus.READY:
            self._icon = self.create_icon('lspserver.ready')
        elif status in [ClientStatus.DOWN, ClientStatus.STARTING,
                        ClientStatus.RESTARTING]:
            self._icon = self.create_icon('lspserver.down')
        self.set_icon()

        # Language
        if lsp_language is not None:
            self.set_value(self.STATUS.format(lsp_language.capitalize()))

    def get_tooltip(self):
        """Reimplementation to get a dynamic tooltip."""
        return self.tooltip

    def get_icon(self):
        return self.create_icon('lspserver.down')

    @Slot()
    def update_status(self, lsp_language=None, status=None):
        """Update status message."""
        # This case can only happen when switching files in the editor
        if lsp_language is None and status is None:
            lsp_language = self.current_language.lower()
            if not self.provider.clients.get(lsp_language, None):
                self.setVisible(False)
            else:
                status = self.provider.clients_statusbar.get(
                    lsp_language,
                    ClientStatus.STARTING
                )
                self.set_status(lsp_language, status)
                self.setVisible(True)
            return

        # Don't update the status in case the editor and LSP languages
        # are different.
        if (self.current_language is None or
                self.current_language.lower() != lsp_language):
            return
        else:
            self.set_status(self.current_language, status)
            self.setVisible(True)

    def set_current_language(self, language):
        self.current_language = language
        self.update_status()
