from operator import itemgetter
from typing import Optional, cast

from libsyntyche.widgets import HBoxLayout, Label, Stretch, mk_signal1
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import Qt

from ..common import Settings


class TagInfoList(QtWidgets.QScrollArea):
    error = mk_signal1(str)
    print_ = mk_signal1(str)

    class TagCountBar(QtWidgets.QWidget):
        def __init__(self, parent: QtWidgets.QWidget,
                     percentage: float) -> None:
            super().__init__(parent)
            self.percentage = percentage

        def paintEvent(self, ev: QtGui.QPaintEvent) -> None:
            right_offset = (1 - self.percentage) * ev.rect().width()
            painter = QtGui.QPainter(self)
            painter.fillRect(ev.rect().adjusted(0, 0, -int(right_offset), 0),
                             painter.background())
            painter.end()

    def __init__(self, parent: QtWidgets.QWidget, settings: Settings) -> None:
        super().__init__(parent)
        self.setSizeAdjustPolicy(self.AdjustToContents)
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                           QtWidgets.QSizePolicy.Expanding)
        self.tag_macros: dict[str, str] = settings.tag_macros.value
        settings.tag_macros.changed.connect(self.set_tag_macros)
        self.panel = QtWidgets.QWidget(self)
        self.panel.setObjectName('tag_info_list_panel')
        self.panel.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                 QtWidgets.QSizePolicy.Maximum)
        layout = QtWidgets.QGridLayout(self.panel)
        layout.setColumnStretch(2, 1)
        layout.setHorizontalSpacing(10)
        # layout.setSizeConstraint(layout.SetMinAndMaxSize)
        # TODO: something less ugly than this
        self.setFixedHeight(200)
        self.panel.setLayout(layout)
        self.setWidget(self.panel)
        self.setWidgetResizable(True)
        self.hide()

    def clear(self) -> None:
        layout = self.panel.layout()
        while not layout.isEmpty():
            item = layout.takeAt(0)
            if item and item.widget() is not None:
                item.widget().deleteLater()

    def set_tag_macros(self, tag_macros: dict[str, str]) -> None:
        self.tag_macros = tag_macros

    def _make_tag(self, tag: str) -> QtWidgets.QWidget:
        tag_label_wrapper = QtWidgets.QWidget(self)
        tag_label = Label(tag, name='tag', parent=tag_label_wrapper)
        tag_label.setStyleSheet('background: #667;')
        HBoxLayout(tag_label, Stretch(), parent=tag_label_wrapper)
        return tag_label_wrapper

    def view_tags(self, tags: list[tuple[str, int]], sort_alphabetically: bool,
                  reverse: bool, name_filter: Optional[str]) -> None:
        self.clear()
        max_count = max(t[1] for t in tags)
        if sort_alphabetically:
            tags.sort(key=itemgetter(0))
        else:
            tags.sort(key=itemgetter(0), reverse=True)
            tags.sort(key=itemgetter(1))
        # If alphabetically, we want to default to ascending,
        # but if we're sorting by usage count, we want it descending.
        if reverse or (not sort_alphabetically and not reverse):
            tags.reverse()
        if name_filter:
            tags = [t for t in tags if name_filter in t[0]]
        layout = cast(QtWidgets.QGridLayout, self.panel.layout())
        for n, (tag, count) in enumerate(tags):
            # Tag name
            layout.addWidget(self._make_tag(tag), n, 0)
            # Tag count
            layout.addWidget(Label(count, name='tag_info_count', parent=self),
                             n, 1, alignment=Qt.AlignBottom)
            # Tag bar
            count_bar = self.TagCountBar(self, count / max_count)
            layout.addWidget(count_bar, n, 2)
        self.show()

    def view_macros(self) -> None:
        # TODO: better view of this
        self.clear()
        layout = cast(QtWidgets.QGridLayout, self.panel.layout())
        for n, (tag, macro) in enumerate(sorted(self.tag_macros.items())):
            # Tag macro name
            layout.addWidget(self._make_tag('@' + tag), n, 0)
            # Tag macro expression
            layout.addWidget(Label(macro, name='tag_info_macro_expression',
                                   word_wrap=True, parent=self), n, 1)
        self.show()
