from PyQt5.QtWidgets import QWidget, QLineEdit, QGraphicsView, QComboBox, \
    QTableView, QHeaderView, QGroupBox, QPushButton, QLabel, QSizePolicy
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QTimer, Qt
from PyQt5.QtGui import QStandardItemModel, QColor, QFont, QStandardItem, QPalette
from PyQt5.Qt import QFontMetrics

from ui.common import open_file, change_color
from settings import Settings
from sql import get_current_competiton

from enum import Enum
import math
import os
import logging


class StartStopButton(QWidget):
    # -- Old and new status
    signalStatus = pyqtSignal(object, object)

    class Status(Enum):
        STOPPED = 1
        RUNNING = 2
        PAUSED = 3

    def __init__(self, btn, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.btn = btn
        self.btn.clicked.connect(self._pressed)
        self.__reset(enabled=False, label='---')

    def setEnabled(self, value):
        self.btn.setEnabled(value)

    def __reset(self, enabled=True, label="Start"):
        self.btn.setText(label)
        self.btn.setChecked(False)
        self.btn.setEnabled(enabled)
        self._status = self.Status.STOPPED
        change_color(self.btn, Settings().panel['start_button'].get(), resource=QPalette.Base)

    def disable(self):
        self.__reset(enabled=False, label='---')

    def enable(self):
        self.__reset(enabled=True, label='Start')

    def _pressed(self):
        old = self._status
        if self.btn.isChecked():
            label = 'Stop'
            color = QColor('red')
            self._status = self.Status.RUNNING
        else:
            label = 'Start'
            color = Settings().panel['start_button'].get()
            self._status = self.Status.PAUSED

        self.btn.setText(label)
        change_color(self.btn, color, resource=QPalette.Button)
        self.signalStatus.emit(old, self._status)

    @property
    def isRunning(self):
        return self._status == self.Status.RUNNING

    @property
    def isPaused(self):
        return self._status == self.Status.PAUSED

    @property
    def isStopped(self):
        return self._status == self.Status.STOPPED

    @property
    def status(self):
        return self._status


class TimerLabel(QTimer):

    INTERVAL = 100

    signalFinished = pyqtSignal()
    signalTimer = pyqtSignal(float, str)

    def __init__(self, label, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._label = label
        self._pause = False
        self._current = -1
        self._log = logging.getLogger('timerlabel')
        self.setInterval(self.INTERVAL)
        self.timeout.connect(self._handler)

    def start(self):
        self._pause = False
        super().start()

    def setPaused(self, value):
        self._pause = value

    def reload(self, seconds):
        self._log.info('Reloaded seconds %i, paused %i' % (seconds, self._pause))
        self._total = self.__sec_to_interval(seconds)
        self._current = self._total
        self._update_label()

    def _update_label(self, emit=True):
        now = self._current / 1000
        minutos = now / 60
        segundos = math.ceil(now % 60)
        value = "%i:%02i" % (minutos, segundos)
        self._label.setText(value)
        if emit:
            self.signalTimer.emit(now, value)

    def _handler(self):
        if self._pause:
            return

        self._current -= self.INTERVAL
        self._update_label()
        if self._current <= 0:
            self.stop()
            self.signalFinished.emit()

    def __sec_to_interval(self, secs):
        return secs * 1000

    @pyqtSlot(int)
    def increase(self, value):
        """
        Allow update only if pending time is greater than one second
        """
        if value > 0 or self._current >= self.__sec_to_interval(1):
            self._current += self.__sec_to_interval(value)
            self._update_label()


class QFileSelectEdit(QLineEdit):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._path = ''

    def config(self, title, filters):
        self._title = title
        self._filters = filters

    def mousePressEvent(self, event):
        value = self.text()
        dpath = os.path.dirname(self._path) if self._path else os.getcwd()
        fpath, _ = open_file(self, self._title, self._filters, path=dpath)
        if fpath and fpath != value:
            self.setText(os.path.basename(fpath))
            self._path = fpath

    def path(self):
        return self._path

    def load(self, fpath):
        self.setText(os.path.basename(fpath))
        self._path = fpath


class KeysGraphicsView(QGraphicsView):
    signalSelect = pyqtSignal(object)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setAcceptDrops(True)
        self.__current = None

    def mousePressEvent(self, ev):
        from ui.keys import Key
        item = self.itemAt(ev.pos())
        if item and type(item) == Key:
            self.__do_select(item)
        else:
            self.__do_select(None)

        QGraphicsView.mousePressEvent(self, ev)

    def __do_select(self, item):
        if item == self.__current:
            return

        if self.__current:
            self.__current.unselect()

        if item:
            item.select()

        self.__current = item
        self.signalSelect.emit(item)

    def reset(self):
        # -- Only reset current item and dont call unselect() as key is removed
        self.__current = None
        self.signalSelect.emit(None)


class DojoCombobox(QComboBox):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__load()

    def __load(self):
        from sql.connection import session
        from sql.models import Dojo

        self.clear()
        self.addItem('---', userData=0)
        for d in session().query(Dojo).order_by(Dojo.name).all():
            self.addItem(d.name, d.dojo_id)

    def value(self, do_raise=True):
        v = self.currentData()
        if not v and do_raise:
            raise ValueError('No se ha seleccionado el dojo')
        return v


class GenderCombobox(QComboBox):

    MANLY = 1
    FEMALE = 2

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__load()

    def __load(self):
        self.addItem('---', userData=0)
        self.addItem('Femenino', userData=self.FEMALE)
        self.addItem('Masculino', userData=self.MANLY)

    def value(self, do_raise=True):
        v = self.currentData()
        if not v and do_raise:
            raise ValueError('No se ha seleccionado el sexo.')
        return v


class MembersTable(QTableView):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.horizontalHeader().setFixedHeight(26);
        self.resizeColumnsToContents()
        self.verticalHeader().setDefaultAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.setToolTipDuration(600000)
        self.setSelectionBehavior(QTableView.SelectRows)
        self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    def setColumns(self, columns):
        self.columns = columns
        self.__createModel()

    def __lastColumn(self):
        return len(self.columns) - 1

    def createHeaders(self):

        # font = QFont()
        # font.setFamily("Monospace")
        # font.setPointSize(10)
        # font.setBold(True)
        # font.setWeight(75)

        index = 0
        for value in self.columns.values():
            item = QStandardItem(value[0])
            #item.setFont(font)
            #item.setBackground(value[1])
            self.__model.setHorizontalHeaderItem(index, item)
            index += 1

        self.setColumnHidden(self.__lastColumn(), True)

    def __createModel(self):
        self.__model = QStandardItemModel(self)
        self.setModel(self.__model)
        self.createHeaders()

    def __appendRowItem(self, items, value):
        item = QStandardItem(str(value))
        item.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        items.append(item)
        return item

    def show(self, items):
        self.__model.clear()
        self.createHeaders()
        for item in items:
            values = []
            for k in self.columns.keys():
                self.__appendRowItem(values, getattr(item, k))
            self.__model.insertRow(self.__model.rowCount(), values)

    def current(self):
        row = self.selectionModel().selectedRows(column=self.__lastColumn())[0]
        return self.__model.itemData(row)[0]


class KeysPositionsGroup(QGroupBox):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    @pyqtSlot(list)
    def update(self, positions):
        #print(positions)
        self.__get_edits()
        for i in range(0, 4):
            self.found_edits[i].setText(positions[i].item.label if positions[i] else "")
            self.found_edits[i].setCursorPosition(0)

        competition = get_current_competiton()
        if not competition.enable_4:
            self.Position4Edit.hide()
            self.label_14.hide()

        if not positions[0]:
            self.hide()
        else:
            self.show()

    def __get_edits(self):
        if not hasattr(self, 'found_edits'):
            self.found_edits = []
            for c in self.findChildren(QLineEdit):
                setattr(self, c.objectName(), c)
                self.found_edits.append(c)
            self.label_14 = self.findChild(QLabel, "label_14")


class PromptLabel(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.label = QLabel('', self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        # -- DONT set the sizepolicy of the parent as leads to weird distortion by Windows
        #self.setSizePolicy(sizePolicy)
        self.label.setSizePolicy(sizePolicy)
        #self.setStyleSheet('border: 1px solid yellow')
        #self.label.setStyleSheet('border: 1px solid white')

    def alignCenter(self):
        self.label.setAlignment(Qt.AlignCenter)

    def refresh(self):
        # -- Dont refresh the label text if was already set before the widget was
        # -- refreshed (this happens when loading settings)
        if not self.label.text():
            self.label.setText(self.toolTip())
        self.label.setFixedSize(self.width(), self.height())

    def setPointSize(self, sz, resize=None, factor_w=1.4, factor_h=1.2, txt_fmt=None):
        font = self.label.font()
        font.setPointSize(sz)
        font.setBold(True)
        font.setFamily("BankGothic Md BT")
        self.label.setFont(font)

        if resize in ('w', '*'):
            metric = QFontMetrics(font)
            w = metric.width(txt_fmt or self.label.text())
            self.setFixedSize(int(factor_w * w), self.height())
            self.label.setFixedSize(self.width(), self.height())
        if resize in ('h', '*'):
            metric = QFontMetrics(font)
            h = metric.height()
            self.setFixedSize(self.width(), int(factor_h * h))
            self.label.setFixedSize(self.width(), self.height())

    def setText(self, txt):
        self.label.setText(txt)

    def setFixedWidth(self, value):
        super().setFixedWidth(value)
        self.label.setFixedWidth(value)

    def mousePressEvent(self, event):
        self.label.setFixedSize(self.width(), self.height())
        #self.setStyleSheet('border: 4px solid yellow')
        print(0, self.objectName(), self.width(), self.height(), "|", self.label.width(), self.label.height())


class LabelFitter(QLabel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def setText(self, txt):
        super().setText(txt)
