#!/usr/bin/env python
# License: GPLv3 Copyright: 2011, Kovid Goyal <kovid@kovidgoyal.net>

import numbers
import textwrap

from qt.core import QCheckBox, QComboBox, QDoubleSpinBox, QGridLayout, QGroupBox, QLabel, QLineEdit, QListView, QSpinBox, Qt, QVBoxLayout, QWidget

from calibre.gui2.preferences.metadata_sources import FieldsModel as FM
from calibre.utils.icu import sort_key
from calibre.utils.localization import _


class FieldsModel(FM):  # {{{
    def __init__(self, plugin):
        FM.__init__(self)
        self.plugin = plugin
        self.exclude = frozenset(['title', 'authors']) | self.exclude
        self.prefs = self.plugin.prefs

    def initialize(self):
        fields = self.plugin.touched_fields
        self.beginResetModel()
        self.fields = []
        for x in fields:
            if not x.startswith('identifier:') and x not in self.exclude:
                self.fields.append(x)
        self.fields.sort(key=lambda x: self.descs.get(x, x))
        self.endResetModel()

    def state(self, field, defaults=False):
        src = self.prefs.defaults if defaults else self.prefs
        return Qt.CheckState.Unchecked if field in src['ignore_fields'] else Qt.CheckState.Checked

    def restore_defaults(self):
        self.beginResetModel()
        self.overrides = {f: self.state(f, True) for f in self.fields}
        self.endResetModel()

    def commit(self):
        ignored_fields = {x for x in self.prefs['ignore_fields'] if x not in self.overrides}
        changed = {k for k, v in self.overrides.items() if v == Qt.CheckState.Unchecked}
        self.prefs['ignore_fields'] = list(ignored_fields.union(changed))


# }}}


class FieldsList(QListView):
    def sizeHint(self):
        return self.minimumSizeHint()


class ConfigWidget(QWidget):
    def __init__(self, plugin):
        QWidget.__init__(self)
        self.plugin = plugin

        self.overl = l = QVBoxLayout(self)
        self.gb = QGroupBox(_('Metadata fields to download'), self)
        if plugin.config_help_message:
            self.pchm = QLabel(plugin.config_help_message)
            self.pchm.setWordWrap(True)
            self.pchm.setOpenExternalLinks(True)
            l.addWidget(self.pchm, 10)
        l.addWidget(self.gb)
        g = QVBoxLayout(self.gb)
        g.setContentsMargins(0, 0, 0, 0)
        self.fields_view = v = FieldsList(self)
        g.addWidget(v)
        v.setFlow(QListView.Flow.LeftToRight)
        v.setWrapping(True)
        v.setResizeMode(QListView.ResizeMode.Adjust)
        self.fields_model = FieldsModel(self.plugin)
        self.fields_model.initialize()
        v.setModel(self.fields_model)
        self.memory = []
        self.widgets = []
        self.l = QGridLayout()
        self.l.setContentsMargins(0, 0, 0, 0)
        l.addLayout(self.l, 100)
        for opt in plugin.options:
            self.create_widgets(opt)

    def create_widgets(self, opt):
        val = self.plugin.prefs[opt.name]
        if opt.type == 'number':
            c = QSpinBox if isinstance(opt.default, numbers.Integral) else QDoubleSpinBox
            widget = c(self)
            widget.setRange(int(min(widget.minimum(), 20 * val)), int(max(widget.maximum(), 20 * val)))
            widget.setValue(val)
        elif opt.type == 'string':
            widget = QLineEdit(self)
            widget.setText(val or '')
        elif opt.type == 'bool':
            widget = QCheckBox(opt.label, self)
            widget.setChecked(bool(val))
        elif opt.type == 'choices':
            widget = QComboBox(self)
            items = list(opt.choices.items())
            items.sort(key=lambda k_v: sort_key(k_v[1]))
            for key, label in items:
                widget.addItem(label, (key))
            idx = widget.findData(val)
            widget.setCurrentIndex(idx)
        widget.setToolTip(textwrap.fill(opt.desc))
        setattr(widget, 'opt', opt)
        self.widgets.append(widget)
        r = self.l.rowCount()
        if opt.type == 'bool':
            self.l.addWidget(widget, r, 0, 1, self.l.columnCount())
        else:
            l = QLabel(opt.label)
            l.setToolTip(widget.toolTip())
            self.memory.append(l)
            l.setBuddy(widget)
            self.l.addWidget(l, r, 0, 1, 1)
            self.l.addWidget(widget, r, 1, 1, 1)

    def commit(self):
        self.fields_model.commit()
        for w in self.widgets:
            if isinstance(w, (QSpinBox, QDoubleSpinBox)):
                val = w.value()
            elif isinstance(w, QLineEdit):
                val = str(w.text())
            elif isinstance(w, QCheckBox):
                val = w.isChecked()
            elif isinstance(w, QComboBox):
                idx = w.currentIndex()
                val = str(w.itemData(idx) or '')
            self.plugin.prefs[w.opt.name] = val
