from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QCheckBox, QTableWidgetSelectionRange, QMessageBox, \
    QHBoxLayout, QWidget

from core.logging_ import Logger
from core.models import Tag
from core.repositories import TagRepository
from core.utils import norm_search
from ui.qt.widgets.sqt.SQTableWidget import SQTableWidget

logger = Logger.get()


class TagsTable(SQTableWidget):
    contentChanged = pyqtSignal()
    tagChecked = pyqtSignal(int)
    tagUnchecked = pyqtSignal(int)

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

        self.cellChanged.connect(self.tagChanged)

    def populate(self, track=None):
        self.setColumnHidden(0, True)
        self.setColumnWidth(1, 45)

        self.cellChanged.disconnect(self.tagChanged)
        while self.rowCount():
            self.removeRow(0)
        super().clear()

        tag_repo = TagRepository()
        tags = tag_repo.get_all()
        checked = []

        if self.selectable:
            if track is not None:
                checked = [t.id for t in tag_repo.get_by_track_id(track.id)]
        else:
            self.setColumnHidden(1, True)

        i = 0
        for tag in tags:
            self.insertRow(i)

            item = QTableWidgetItem()
            item.setData(0, tag.id)
            self.setItem(i, 0, item)

            if self.selectable:
                widget = QWidget()
                checkBox = QCheckBox()
                if tag.id in checked:
                    checkBox.setChecked(True)
                layout = QHBoxLayout(widget)
                layout.addWidget(checkBox)
                layout.setAlignment(Qt.AlignCenter)
                layout.setContentsMargins(0, 0, 0, 0)
                widget.setLayout(layout)
                checkBox.tag_id = tag.id
                checkBox.stateChanged.connect(self.tagStateChanged)
                self.setCellWidget(i, 1, widget)

            self.setItem(i, 2, QTableWidgetItem(tag.label))
            i += 1

        self.cellChanged.connect(self.tagChanged)

    def add(self):
        tag_repo = TagRepository()
        tag = Tag()
        tag.label = "Mon étiquette"
        tag_repo.create(tag, True)
        self.populate()
        self.selectTag(tag.id)
        self.contentChanged.emit()

    def selectTag(self, tag_id):
        for i in self.rows():
            item = self.item(i, 0)
            if item.data(0) == tag_id:
                self.setCurrentItem(item)
                self.setRangeSelected(QTableWidgetSelectionRange(i, 0, i, 2), True)
                break

    def removeSelected(self):
        row = self.currentRow()
        tag_id = self.item(row, 0).data(0)
        tag_repo = TagRepository()
        tag = tag_repo.get_by_id(tag_id)
        tag_repo.delete(tag, True)
        self.populate()
        self.contentChanged.emit()

    def tagChanged(self, row, column):
        tag_id = self.item(row, 0).data(0)

        if column == 1:
            # tag has been checked / unchecked
            print("checked")

        elif column == 2:
            # tag label has been updated
            new_label = self.item(row, 2).text()
            self.tagLabelUpdated(tag_id, new_label)

    def tagLabelUpdated(self, tag_id, new_label):
        tag_repo = TagRepository()
        tag = tag_repo.get_by_id(tag_id)
        tag.label = new_label
        tag_repo.commit()
        self.contentChanged.emit()

    def tagStateChanged(self, state):
        checkBox = self.sender()
        if state == Qt.Unchecked:
            self.tagUnchecked.emit(checkBox.tag_id)
        else:
            self.tagChecked.emit(checkBox.tag_id)

    def selectedTags(self):
        if not self.selectable:
            raise RuntimeError("TagsTable is not selectable")
        selected = []
        for i in self.rows():
            checked = self.cellWidget(i, 1).isChecked()
            if checked:
                tag_id = self.item(i, 0).data(0)
                selected.append(tag_id)
        return selected

    def filter(self, search):
        for i in self.rows():
            hide = norm_search(search) not in norm_search(self.item(i, 2).text())
            self.setRowHidden(i, hide)
