from qtpy import QtCore
from qtpy.QtWidgets import (
    QTableView,
    QHeaderView,
)

from qtpy import QtGui


class SelectableChannelsItem(QtGui.QStandardItem):
    """
    Standard table item object representation.
    """
    def __init__(self, *args, **kwargs):
        super(SelectableChannelsItem, self).__init__(*args, **kwargs)

        self.setEditable(False)


class SelectableChannelsListTable(QTableView):
    """
    Table object representation for selecting channels while doing login to Team Edition instance.
    """
    NAME_INDEX = 0
    MIRROR_INDEX = 1
    PRIVACY_INDEX = 2
    OWNERS_INDEX = 3
    DEFAULT_CHANNELS_INDEX = 4
    CHANNELS_INDEX = 5
    MIRROR_COUNT_INDEX = 6
    TOTAL_INDEX_COUNT = 7

    TABLE_HEADERS = ['Name', 'Mirror', 'Privacy', 'Owners', 'Add to default_channels', 'Add to channels']

    def __init__(self, parent, table_data, channels=None, default_channels=None):
        super(SelectableChannelsListTable, self).__init__()

        if not channels:
            channels = []
        if not default_channels:
            default_channels = []

        self.MIRROR_ORDERING = QtCore.Qt.DescendingOrder

        self.parent = parent
        self.apply_data_model(table_data, channels, default_channels)

        for index in range(self.TOTAL_INDEX_COUNT):
            self.horizontalHeader().setSectionResizeMode(index, QHeaderView.ResizeToContents)

        self.horizontalHeader().setStretchLastSection(True)
        self.verticalHeader().setVisible(False)
        self.setColumnHidden(self.MIRROR_COUNT_INDEX, True)
        self.setSortingEnabled(True)
        self.sortByColumn(self.MIRROR_COUNT_INDEX, QtCore.Qt.DescendingOrder)

        self.horizontalHeader().resizeSection(self.CHANNELS_INDEX, 120)
        self.horizontalHeader().sectionClicked.connect(self.apply_mirror_ordering)

    def switch_mirror_ordering(self):
        """
        Switches the mirror ordering trigger ASC/DESC.
        """
        if self.MIRROR_ORDERING == QtCore.Qt.DescendingOrder:
            self.MIRROR_ORDERING = QtCore.Qt.AscendingOrder
        else:
            self.MIRROR_ORDERING = QtCore.Qt.DescendingOrder

    def apply_mirror_ordering(self, index):
        """
        Handles the ordering action.
        If ordering happens on the 'Mirror' column, actually filtering is happen on
        hidden column which holds the 'Mirror count'.
        Also updates the trigger which holds the latest
        applied ordering (i.e. ASC/DESC).
        """
        if index == self.MIRROR_INDEX:
            self.switch_mirror_ordering()
            self.sortByColumn(self.MIRROR_COUNT_INDEX, self.MIRROR_ORDERING)

    def apply_data_model(self, table_data, channels, default_channels):
        """
        Creates the model data for the table depending on passed data in 'table_data' attribute.

        :param dict[str, str/int] table_data: The data which will be hold in model.
        :param list[str] channels: List of 'channels' names which must be checked by default.
        :param list[str] default_channels: List of 'default_channels' which must be checked by default.
        """
        model = QtGui.QStandardItemModel()
        model.setHorizontalHeaderLabels(self.TABLE_HEADERS)

        for row, channel in enumerate(table_data):
            model.setItem(row, self.NAME_INDEX, SelectableChannelsItem(channel['name']))
            model.setItem(row, self.MIRROR_INDEX, self.generate_mirror_item(channel['mirror_count']))
            model.setItem(row, self.PRIVACY_INDEX, SelectableChannelsItem(channel['privacy']))
            model.setItem(row, self.OWNERS_INDEX, SelectableChannelsItem('\n'.join(channel['owners'])))
            model.setItem(row, self.MIRROR_COUNT_INDEX, SelectableChannelsItem(str(channel['mirror_count'])))

            default_channels_is_checked = True if channel['name'] in default_channels else False
            channels_is_checked = True if channel['name'] in channels else False

            model.setItem(row, self.DEFAULT_CHANNELS_INDEX, self.generate_checkable_item(default_channels_is_checked))
            model.setItem(row, self.CHANNELS_INDEX, self.generate_checkable_item(channels_is_checked))

        self.setModel(model)

    @staticmethod
    def generate_mirror_item(mirror_count):
        """
        Creates a table item with a disable checkbox and empty string.
        Represents the state of a channel if it has any mirrors.

        :param str mirror_count: The mirror count number.

        :return SelectableChannelsItem: The created table item object.
        """
        is_checked = bool(mirror_count)

        mirror_item = SelectableChannelsItem()
        mirror_item.setCheckable(True)
        mirror_item.setEnabled(False)

        if is_checked:
            mirror_item.setCheckState(QtCore.Qt.Checked)

        return mirror_item

    @staticmethod
    def generate_checkable_item(is_checked=False):
        """
        Creates a table item with a checkbox and empty string.

        :param bool is_checked: Defines if the checkbox must be checked.

        :return SelectableChannelsItem: The created table item object.
        """
        checkable_item = SelectableChannelsItem()
        checkable_item.setCheckable(True)
        checkable_item.setTextAlignment(QtCore.Qt.AlignCenter)

        if is_checked:
            checkable_item.setCheckState(QtCore.Qt.Checked)

        return checkable_item

    def get_selected_channels(self):
        """
        Returns the lists with 'default_channels' and 'channels' names fetched from the model,
        where on row 4 and 5 (default_channels and channels) checkboxes are in the checked state.

        :return tuple[list[str], list[str]]
        """
        default_channels = []
        channels = []

        for row in range(self.model().rowCount()):
            data_index = self.model().index(row, self.NAME_INDEX)

            if self.model().item(row, self.DEFAULT_CHANNELS_INDEX).checkState() == QtCore.Qt.Checked:
                default_channels.append(self.model().data(data_index))

            if self.model().item(row, self.CHANNELS_INDEX).checkState() == QtCore.Qt.Checked:
                channels.append(self.model().data(data_index))

        return default_channels, channels
