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

# yapf: disable

from __future__ import absolute_import, division, print_function

# Standard library imports
from collections import OrderedDict
import os
import shutil

# Third party imports
from qtpy.QtCore import Qt, QTimer, Signal
from qtpy.QtWidgets import QHBoxLayout, QMenu, QSizePolicy, QVBoxLayout

# Local imports
from anaconda_navigator.api.anaconda_api import AnacondaAPI
from anaconda_navigator.config import CONF, PROJECTS_PATH
from anaconda_navigator.utils.analytics import GATracker
from anaconda_navigator.utils.logs import logger
# from anaconda_navigator.utils.logs import logger
from anaconda_navigator.utils.styles import load_style_sheet
from anaconda_navigator.widgets import (ButtonToolNormal,
                                        FrameEnvironmentsList,
                                        FrameEnvironmentsPackages,
                                        FrameTabHeader, QToolButton,
                                        WidgetBase)
from anaconda_navigator.widgets.dialogs import MessageBoxError
from anaconda_navigator.widgets.dialogs.projects import (CreateDialog,
                                                         ImportDialog,
                                                         RemoveDialog)
from anaconda_navigator.widgets.helperwidgets import LineEditSearch
from anaconda_navigator.widgets.lists.projects import (ListItemEnv,
                                                       ListWidgetEnv)
from anaconda_navigator.widgets.projects import ProjectsWidget


# yapf: enable


class ButtonToggleCollapse(QToolButton):
    """Button to collapse the environment list."""

    def __init__(self, *args, **kwargs):
        """Button to collapse the environment list."""
        super(ButtonToggleCollapse, self).__init__(*args, **kwargs)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setFocusPolicy(Qt.NoFocus)
        self.setCheckable(True)

        self.clicked.connect(self._update_icon)

    def setProperty(self, name, value):
        """Override Qt method."""
        QToolButton.setProperty(self, name, value)
        self.style().unpolish(self)
        self.style().polish(self)
        self.update()

    def _update_icon(self):
        self.setProperty('checked', self.isChecked())


class ProjectsTab(WidgetBase):
    """Projects management tab."""
    sig_apps_changed = Signal(str)
    sig_apps_updated = Signal()
    sig_project_updated = Signal()
    sig_status_updated = Signal(str, int, int, int)

    def __init__(self, parent=None):
        super(ProjectsTab, self).__init__(parent)

        # Create projects path if not existent
        if not os.path.isdir(PROJECTS_PATH):
            os.makedirs(PROJECTS_PATH)

        self.api = AnacondaAPI()
        self.active_project_path = None
        self.last_env_prefix = None
        self.last_env_name = None
        self.previous_environments = None
        self.tracker = GATracker()
        self.metadata = {}
        self.config = CONF

        active_channels = CONF.get('main', 'conda_active_channels')
        if not active_channels:
            channels = self.api.conda_get_condarc_channels()
            CONF.set('main', 'conda_active_channels', channels)

        # Widgets
        self.button_create = ButtonToolNormal(text="Create")
        self.button_import = ButtonToolNormal(text="Import")
        self.button_remove = ButtonToolNormal(text="Remove")

        self.frame_environments_list = FrameEnvironmentsList(self)
        self.frame_environments_packages = FrameEnvironmentsPackages(self)
        self.frame_header_left = FrameTabHeader()
        self.frame_header_right = FrameTabHeader()

        self.button_toggle_collapse = ButtonToggleCollapse()

        self.list_environments = ListWidgetEnv()
        self.projects_widget = ProjectsWidget()
        self.menu_list = QMenu()
        self.text_search = LineEditSearch()
        self.timer_environments = QTimer()

        # Widgets setup
        self.frame_environments_list.is_expanded = True
        self.list_environments.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.list_environments.setContextMenuPolicy(Qt.CustomContextMenu)
        self.text_search.setPlaceholderText("Search Projects")
        self.text_search.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.timer_environments.setInterval(3000)
        self.timer_environments.timeout.connect(self.refresh_projects_list)
        self.timer_environments.start()

        self.button_create.setObjectName("create")
        self.button_import.setObjectName("import")
        self.button_remove.setObjectName("remove")

        # Layouts
        layout_header_left = QVBoxLayout()
        layout_header_left.addWidget(self.text_search)
        self.frame_header_left.setLayout(layout_header_left)

        layout_buttons = QHBoxLayout()
        layout_buttons.addWidget(self.button_create)
        #        layout_buttons.addWidget(self.button_clone)
        layout_buttons.addWidget(self.button_import)
        layout_buttons.addWidget(self.button_remove)

        layout_list_buttons = QVBoxLayout()
        layout_list_buttons.addWidget(self.frame_header_left)
        layout_list_buttons.addWidget(self.list_environments)
        layout_list_buttons.addLayout(layout_buttons)
        self.frame_environments_list.setLayout(layout_list_buttons)

        layout_packages = QHBoxLayout()
        layout_packages.addWidget(self.projects_widget)
        self.frame_environments_packages.setLayout(layout_packages)

        layout_main = QHBoxLayout()
        layout_main.addWidget(self.frame_environments_list, 10)
        layout_main.addWidget(self.button_toggle_collapse, 1)
        layout_main.addWidget(self.frame_environments_packages, 30)

        self.setLayout(layout_main)
        self.update_style_sheet()

        # Signals
        self.button_toggle_collapse.clicked.connect(self.expand_collapse)
        self.button_create.clicked.connect(self.create_project)
        self.button_import.clicked.connect(self.import_project)
        self.button_remove.clicked.connect(self.remove_project)
        self.list_environments.sig_item_selected.connect(self.load_project)
        self.text_search.textChanged.connect(self.filter_projects)

        self.refresh()

    def refresh(self):
        """Refresh buttons based on project count."""
        projects = self.projects
        active = bool(projects)
        if not active:
            self.projects_widget.clear()
        self.projects_widget.setVisible(active)
        self.button_remove.setEnabled(active)
        self.projects_widget.setEnabled(active)

    @property
    def projects(self):
        """Return an ordered dictionary of all existing projects."""
        if not os.path.isdir(PROJECTS_PATH):
            os.makedirs(PROJECTS_PATH)

        folders = [
            i for i in os.listdir(PROJECTS_PATH)
            if os.path.isdir(os.path.join(PROJECTS_PATH, i))
        ]
        projects = OrderedDict()
        for folder in folders:
            files = os.listdir(os.path.join(PROJECTS_PATH, folder))
            if 'anaconda-project.yml' in files:
                project_path = os.path.join(PROJECTS_PATH, folder)
                # project = self.api.project_load(project_path)
                # projects[project.name] = project_path
                projects[folder] = project_path
        return projects

    @property
    def environments(self):
        """
        Return an ordered dictionary of all existing named environments.

        The dictionary includes the root environment as the first entry.
        """
        environments = OrderedDict()
        environments_prefix = sorted(self.api.conda_get_envs(log=False))
        environments['root'] = self.api.ROOT_PREFIX

        for prefix in environments_prefix:
            name = os.path.basename(prefix)
            environments[name] = prefix

        return environments

    @property
    def current_project_name(self):
        return self.list_environments.currentItem().text()

    @property
    def current_project_path(self):
        return self.list_environments.currentItem().prefix()

    def refresh_projects_list(self, startup=False):
        """Reload the project listing."""
        selected_project_path = None
        current_index = self.list_environments.currentIndex()
        if current_index is not None:
            item = self.list_environments.item(current_index)
            selected_project_path = item.prefix()

        self.list_environments.clear()
        item_row_to_select = 0
        projects = self.projects
        for i, project_name in enumerate(projects):
            project_path = projects[project_name]
            item = ListItemEnv(project_name, prefix=project_path)
            item.button_options.setVisible(False)
            self.list_environments.addItem(item)
            if project_path == self.active_project_path:
                item_row_to_select = i

        self.list_environments.setCurrentRow(item_row_to_select, loading=False)
        count = self.list_environments.count()

        if startup and count != 0:
            self.load_project(self.list_environments.item(item_row_to_select))
        elif (count != 0 and
                self.active_project_path != selected_project_path and
                not startup):
            self.load_project(self.list_environments.item(item_row_to_select))
        self.filter_projects()
        self.refresh()

    def _project_created(self, worker, output, error):
        """Callback for create/import project method."""
        if worker.type == 'create':
            project_type = 'creation'
        else:
            project_type = 'import'

        if error or (output and output.problems):
            error = ''
            if output and output.problems:
                error = '\n'.join(output.problems)
            else:
                error = error
            logger.error(str(error))
            shutil.rmtree(output.directory_path)
            msg_box = MessageBoxError(
                title='Project {0} '
                'error'.format(worker.type),
                text='Project {0} failed due to:'
                ''.format(project_type),
                error=error,
            )
            msg_box.exec_()
        else:
            self.active_project_path = output.directory_path
        self.refresh_projects_list()

    def load_project(self, item):
        """Load project."""
        item.set_loading(False)
        project_path = item.prefix()
        self.projects_widget.load_project(project_path)
        self.active_project_path = project_path

    def create_project(self):
        """Create new basic project."""
        dlg = CreateDialog(parent=self, projects=self.projects)
        self.tracker.track_page(
            '/projects/create', pagetitle='Create new project dialog'
        )

        if dlg.exec_():
            name = dlg.name
            path = os.path.join(PROJECTS_PATH, name)

            if os.path.isdir(path):
                return
            else:
                os.makedirs(path)

            worker = self.api.project_create(
                path, name=name, make_directory=False
            )
            worker.sig_finished.connect(self._project_created)
            worker.type = 'create'

        self.tracker.track_page('/projects')

    def import_project(self):
        """Create new basic project."""
        dlg = ImportDialog(parent=self, projects=self.projects)
        self.tracker.track_page(
            '/projects/import', pagetitle='Import project dialog'
        )

        if dlg.exec_():
            name = dlg.name
            path = os.path.join(PROJECTS_PATH, name)
            folder_file_path = dlg.path

            if os.path.isdir(path):
                return
            else:
                if os.path.isdir(folder_file_path):
                    shutil.copytree(folder_file_path, path)
                else:
                    os.mkdir(path)
                    file_path = os.path.join(
                        path,
                        os.path.basename(folder_file_path),
                    )
                    shutil.copyfile(folder_file_path, file_path)

                worker = self.api.project_create(
                    path, name=name, make_directory=False
                )
                worker.sig_finished.connect(self._project_created)
                worker.type = 'import'

        self.tracker.track_page('/projects')

    def remove_project(self):
        """Create new basic project."""
        dlg = RemoveDialog(parent=self, project=self.current_project_name)
        self.tracker.track_page(
            '/projects/remove', pagetitle='Remove project dialog'
        )

        if dlg.exec_():
            path = self.current_project_path
            self.projects_widget.before_delete()
            try:
                shutil.rmtree(path)
            except Exception:
                pass
            self.refresh_projects_list()

        self.tracker.track_page('/projects')

    def update_style_sheet(self, style_sheet=None):
        """
        """
        if style_sheet is None:
            style_sheet = load_style_sheet()
        self.setStyleSheet(style_sheet)
#        self.text_search.update_style_sheet(style_sheet)

#        self.list_projects.setFrameStyle(QFrame.NoFrame)
#        self.list_projects.setFrameShape(QFrame.NoFrame)
#        self.list_projects.setStyleSheet(style_sheet)
#        for i in range(self.list_projects.count()):
#            item = self.list_projects.item(i)
#            item.setSizeHint(QSize(60, 60))
#        self.list_projects.repaint()

    def setup_tab(self, startup=True):
        """
        """
        self.refresh_projects_list(startup=startup)

#        self.load_projects()
#        self.project_widget.setDisabled(True)
#        self.load_last_active_project()

    def ordered_widgets(self, next_widget=None):
        """Return a list of the ordered widgets."""
        #        if next_widget is not None:
        #            self.packages_widget.table_last_row.add_focus_widget(next_widget)
        ordered_widgets = [self.text_search, ]
        #        ordered_widgets += self.list_environments.ordered_widgets()
        #        ordered_widgets += [
        #            self.button_create,
        #            self.button_clone,
        #            self.button_import,
        #            self.button_remove,
        #            self.packages_widget.combobox_filter,
        #            self.packages_widget.button_channels,
        #            self.packages_widget.button_update,
        #            self.packages_widget.textbox_search,
        #            #            self.packages_widget.table_first_row,
        #            self.packages_widget.table,
        #            self.packages_widget.table_last_row,
        #            self.packages_widget.button_apply,
        #            self.packages_widget.button_clear,
        #            self.packages_widget.button_cancel,
        #        ]
        return ordered_widgets

    # --- Helpers
    # -------------------------------------------------------------------------
    def expand_collapse(self):
        """Expand or collapse the environment selector."""
        if self.frame_environments_list.is_expanded:
            self.frame_environments_list.hide()
            self.frame_environments_list.is_expanded = False
        else:
            self.frame_environments_list.show()
            self.frame_environments_list.is_expanded = True

    def filter_projects(self, text=None):
        """Filter projects by name."""
        text = self.text_search.text().lower()
        for i in range(self.list_environments.count()):
            item = self.list_environments.item(i)
            item.setHidden(text not in item.text().lower())

            if not item.widget.isVisible():
                item.widget.repaint()


def local_test():
    """Run local test for project tab."""
    from anaconda_navigator.utils.qthelpers import qapplication
    app = qapplication()
    w = ProjectsTab()
    w.showMaximized()
    app.exec_()


if __name__ == "__main__":
    local_test()
