# coding: utf-8
import logging
from collections import namedtuple

from PyQt5.QtCore import pyqtSignal, QObject, Qt, QRectF, pyqtProperty
from PyQt5.QtGui import (QPaintEvent, QPainter, QColor, QLinearGradient,
                         QPainterPath)
from PyQt5.QtWidgets import (QWidget, QSlider, QFormLayout, QGridLayout, QLabel,
                             QSpinBox)

from mhw_armor_edit.ftypes.kire import KireEntry

log = logging.getLogger(__name__)

KIRE_MAX_VALUE = 400
KireGaugeColors = namedtuple("KireGaugeColors", (
    "red",
    "orange",
    "yellow",
    "green",
    "blue",
    "white",
    "purple",
))


class KireGaugeModel(QObject):
    changed = pyqtSignal()

    def __init__(self, red=0, orange=0, yellow=0, green=0, blue=0, white=0,
                 purple=0, parent=None):
        super().__init__(parent)
        self.red = red
        self.orange = orange
        self.yellow = yellow
        self.green = green
        self.blue = blue
        self.white = white
        self.purple = purple

    def set_value(self, color_attr, value):
        setattr(self, color_attr, value)
        self.changed.emit()

    def get_value(self, color_attr):
        return getattr(self, color_attr, 0)

    def get_percent(self, color_attr):
        return self.get_value(color_attr) / KIRE_MAX_VALUE

    def set_red(self, value):
        """setter for signal binding"""
        self.set_value("red", value)

    def set_orange(self, value):
        """setter for signal binding"""
        self.set_value("orange", value)

    def set_yellow(self, value):
        """setter for signal binding"""
        self.set_value("yellow", value)

    def set_green(self, value):
        """setter for signal binding"""
        self.set_value("green", value)

    def set_blue(self, value):
        """setter for signal binding"""
        self.set_value("blue", value)

    def set_white(self, value):
        """setter for signal binding"""
        self.set_value("white", value)

    def set_purple(self, value):
        """setter for signal binding"""
        self.set_value("purple", value)


class KireGaugeModelEntryAdapter(KireGaugeModel):
    changed = pyqtSignal()

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

    def set_entry(self, entry):
        self.entry = entry
        self.changed.emit()

    def set_value(self, color_attr, value):
        setattr(self.entry, color_attr, value)
        self.changed.emit()

    def get_value(self, color_attr):
        return getattr(self.entry, color_attr, 0)


def _gradient(height, color1, color2):
    grad = QLinearGradient(0, 0, 0, height)
    grad.setColorAt(0.0, color1)
    grad.setColorAt(1.0, color2)
    return grad


def _rounded_rect_clip(rect, roundness):
    cp = QPainterPath()
    cp.addRoundedRect(QRectF(rect), roundness, roundness)
    return cp


class KireGauge(QWidget):
    MARGIN = 2
    colors = KireGaugeColors(
        QColor(220, 60, 60),
        QColor(220, 180, 60),
        QColor(220, 220, 60),
        QColor(60, 220, 60),
        QColor(60, 80, 220),
        QColor(240, 240, 240),
        QColor(140, 60, 220)
    )
    bg_dark = QColor(40, 40, 40)
    bg_light = QColor(80, 80, 80)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setMinimumSize(120, 24)
        self.setContentsMargins(self.MARGIN, self.MARGIN, self.MARGIN, self.MARGIN)
        self.model: KireGaugeModel = None

    def handle_model_updated(self):
        self.repaint()

    def set_model(self, model):
        if self.model:
            self.model.changed.disconnect(self.handle_model_updated)
        self.model = model
        self.model.changed.connect(self.handle_model_updated)

    def paintEvent(self, paint_event: QPaintEvent):
        super().paintEvent(paint_event)
        p = QPainter()
        p.begin(self)
        self.draw(p)
        p.end()

    def draw(self, p: QPainter):
        p.setRenderHint(QPainter.Antialiasing)
        crect = self.contentsRect()
        p.setClipPath(_rounded_rect_clip(self.rect(), self.MARGIN * 2))
        p.fillRect(self.rect(),
                   _gradient(self.height(), self.bg_dark, self.bg_light))
        if self.model is None:
            return
        for attr in reversed(KireGaugeColors._fields):
            value = self.model.get_percent(attr)
            if value == 0:
                continue
            color = getattr(self.colors, attr)
            p.setClipPath(_rounded_rect_clip(crect, self.MARGIN))
            p.fillRect(crect.x(), crect.y(),
                       crect.width() * value, crect.height(),
                       _gradient(crect.height(), color.lighter(), color))


class KireWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QGridLayout(self)
        layout.setColumnStretch(0, 0)
        layout.setColumnStretch(1, 1)
        layout.setColumnStretch(2, 0)
        self.setLayout(layout)
        self.gauge = KireGauge(self)
        self.connections = {}
        layout.addWidget(QLabel("Gauge"), 0, 0)
        layout.addWidget(self.gauge, 0, 1, 1, 2)
        for row, color_attr in enumerate(KireGaugeColors._fields):
            slider = QSlider(self)
            slider.setProperty("color", color_attr)
            slider.setOrientation(Qt.Horizontal)
            slider.setMinimum(0)
            slider.setMaximum(KIRE_MAX_VALUE)
            slider.setTickInterval(50)
            slider.setTickPosition(QSlider.TicksBelow)
            num_input = QSpinBox()
            num_input.setMinimum(0)
            num_input.setMaximum(KIRE_MAX_VALUE)
            slider.valueChanged.connect(num_input.setValue)
            num_input.valueChanged.connect(slider.setValue)
            layout.addWidget(QLabel(color_attr.capitalize()), row + 1, 0)
            layout.addWidget(slider, row + 1, 1)
            layout.addWidget(num_input, row + 1, 2)

    @pyqtProperty('QVariant', user=True)
    def value(self):
        """pyqtProperty for data widget mapper bindings"""
        try:
            return self.gauge.model.entry
        except AttributeError:
            return None

    @value.setter
    def value(self, value: KireEntry):
        """pyqtProperty for data widget mapper bindings"""
        self.setDisabled(value is None)
        self.gauge.model.set_entry(value)
        for slider in self.findChildren(QSlider):
            color_attr = slider.property("color")
            slider.setValue(self.gauge.model.get_value(color_attr))

    def set_model(self, model):
        self.gauge.set_model(model)
        for slider in self.findChildren(QSlider):
            color_attr = slider.property("color")
            value_setter = getattr(model, f"set_{color_attr}")
            if self.connections.get(color_attr):
                slider.valueChanged.disconnect(self.connections[color_attr])
            self.connections[color_attr] = \
                slider.valueChanged.connect(value_setter)
            slider.setValue(model.get_value(color_attr))