from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import QMessageBox, QMenu, QWidget
from utils.widgets.members_table import MembersTable
from controllers.base_controller import BaseController
from model.distribution import Distribution
from model.member import Member
from utils.database import IntegrityError
from utils.globals import Global
from utils.qtmodels.distributions_tree_model import DistributionTreeModel
from utils.widgets.editable_title_widget import EditableTitle
from windows import groupedit


class GroupEdit(BaseController, QWidget, groupedit.Ui_Form):
    def __init__(self, main_window, group, parent=None):
        """
        Cotnroller of group edit window
        :param main_window: main application window
        :param group: (Group) group to be displayed  
        :param parent: parent widget for qt
        """
        super(GroupEdit, self).__init__(parent)
        self.setupUi(self)
        self.main_window = main_window

        self.group = group
        self.membersTable = MembersTable(
            num_of_buttons=2,
            button_definitions=({'text':"", 'tooltip':self.tr("Přehled"), 'icon':":/icons/eye.svg"},
                                {'text':"", 'tooltip':self.tr("Smazat člena"), 'icon':":/icons/minus.svg"},),
            data=group.members)
        self.updateMemberCount()
        self.layoutMembers.insertWidget(0, self.membersTable)
        self.treeDistributions.setModel(DistributionTreeModel(group.distributions))

        title = EditableTitle(group.name, self)
        self.layoutName.replaceWidget(self.widgetTitle, title)
        self.widgetTitle = title

        self.btnExpandAll.clicked.connect(self.onExpandAllClicked)
        self.expanded = False

        # signals
        self.btnDelete.clicked.connect(self.deleteGroup)
        self.btnAddNew.clicked.connect(self.addNewMember)
        self.editNewMemberName.returnPressed.connect(self.addNewMember)
        self.btnDistribute.clicked.connect(self.distribute)
        self.membersTable.btnClicked.connect(self.onTableMembersBtnClicked)
        self.membersTable.itemDoubleClicked.connect(self.goToMemberOverview)
        self.widgetTitle.textConfirmed.connect(self.changeGroupName)
        self.treeDistributions.expanded.connect(self.expandChildren)
        self.treeDistributions.customContextMenuRequested.connect(self.onContextMenuRequested)

    def reloadData(self):
        """
        reload data from database
        """
        self.group = Global.db.getGroupById(self.group.id_)
        self.membersTable.changeData(self.group.members)
        self.updateMemberCount()
        self.treeDistributions.setModel(DistributionTreeModel(self.group.distributions))

    @pyqtSlot(str)
    def changeGroupName(self, name):
        """
        change name of group, if it's not unique, show error message
        :param name: new group name
        """
        try:
            self.group.rename(name)
        except IntegrityError as e:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Skupina s tímto jménem již existuje")
            msg.setWindowTitle(self.tr("Nelze přejmenovat skupinu"))
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec()
            self.widgetTitle.editMode()

    @pyqtSlot()
    def deleteGroup(self):
        """
        Show confirmation prompt and delete group + go back after 
        """
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Question)
        msg.setWindowTitle(self.tr("Opravdu?"))
        msg.setText(self.tr("Opravdu chcete smazat skupinu " + self.group.name + "?"))
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        if msg.exec() == QMessageBox.Ok:
            self.group.delete()
            self.main_window.dataChanged()
            self.main_window.goBack()

    @pyqtSlot()
    def addNewMember(self):
        """
        Add member specified in self.editNewMemberName, if not unique, show error message
        """
        name = self.editNewMemberName.text().strip()
        if len(name) == 0:
            return
        try:
            self.group.addMember(name)
            self.main_window.dataChanged()
        except IntegrityError as e:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Critical)
            msg.setText(self.tr("Tento člen již v této skupině existuje."))
            msg.setWindowTitle(self.tr("Nelze přidat člena"))
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec()
        finally:
            # prepare for inserting another one
            self.editNewMemberName.clear()
            self.editNewMemberName.setFocus()

        self.membersTable.changeData(self.group.members)
        self.updateMemberCount()

    def updateMemberCount(self):
        """
        update member count label 
        """
        self.lblMemberCount.setText(str(self.group.member_count))

    @pyqtSlot()
    def distribute(self):
        """
        go to distribution setup for this group
        """
        self.main_window.goToDistributionSetup(self.group)

    @pyqtSlot(Member, int)
    def onTableMembersBtnClicked(self, member, btn_nr):
        """
        Slot for buttons from tableMembers
        :param member: 
        :param btn_nr: 
        """
        if btn_nr == 0:
            self.goToMemberOverview(member)
        elif btn_nr == 1:
            self.deleteMember(member)

    def goToMemberOverview(self, member):
        """
        go to member overview
        :param member: 
        """
        self.main_window.goToMemberOverview(member)

    def deleteMember(self, member):
        """
        delete member
        :param member:
        """
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Question)
        msg.setWindowTitle(self.tr("Opravdu?"))
        msg.setText(self.tr("Opravdu chcete smazat člena " + member.name + "?"))
        msg.setInformativeText(self.tr("Člen bude zároveň smazán i ze všech rozdělení, ve kterých byl."))
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        if msg.exec() == QMessageBox.Ok:
            member.delete()
            self.main_window.dataChanged()
            self.reloadData()

    def onExpandAllClicked(self):
        """
        expand everything in treeHistory and change button to 'hide all'
        or if the button already is 'hide all' do the opposite
        """
        if self.expanded:
            self.treeDistributions.collapseAll()
            self.btnExpandAll.setText(self.tr("Rozbalit vše"))
        else:
            self.treeDistributions.expandAll()
            self.btnExpandAll.setText(self.tr("Sbalit vše"))
        self.expanded = not self.expanded

    def expandChildren(self, index):
        """
        expand all children of given index in self.treeDistribution
        :param index: 
        """
        for i in range(index.model().rowCount(index)):
            child = index.model().index(i, 0, index)
            self.treeDistributions.expand(child)

    def onContextMenuRequested(self, point):
        """
        construct context menu (only if clicked on distribution)
        :param point: 
        """
        element = self.treeDistributions.model().data(self.treeDistributions.indexAt(point), Qt.UserRole)
        if not isinstance(element, Distribution):
            return
        menu = QMenu(self.treeDistributions)
        menu.addAction(self.tr("Upravit"), lambda: self.goToDistributionEdit(element))
        menu.addAction(self.tr("Duplikovat"), lambda: self.duplicate(element))
        menu.exec_(self.treeDistributions.mapToGlobal(point))

    def goToDistributionEdit(self, distribution):
        """
        go to distribution edit window
        :param distribution:
        """
        self.main_window.goToDistributionEdit(distribution, self.group)

    def duplicate(self, distribution):
        """
        duplicate distribution and go to it's overview
        :param distribution: 
        """
        self.main_window.goToDistributionOverview(
            {team.name: team.members for team in distribution.teams},
            self.group,
            distribution.name
        )