import logging
import os
from qgis.PyQt.QtWidgets import QComboBox
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QWidget, QHBoxLayout, QToolButton, QMenu, QDialog
from qgis.PyQt.QtCore import pyqtSlot, Qt, QSize, QEvent
from qgis.gui import QgsCheckableComboBox
from qgis.utils import iface
from SAGisXPlanung import Session, BASE_DIR
from SAGisXPlanung.XPlan.codelists import CodeListValue
from SAGisXPlanung.XPlanungItem import XPlanungItem
from SAGisXPlanung.gui.style import load_svg
from SAGisXPlanung.gui.widgets.inputs.input_widgets import QComboBoxNoScroll
from SAGisXPlanung.gui.widgets.inputs.base_input_element import BaseInputElement, XPlanungInputMeta
from SAGisXPlanung.utils import confirmObjectDeletion
logger = logging.getLogger(__name__)

class QAddRelationDropdown(QWidget, BaseInputElement, metaclass=XPlanungInputMeta):

    def __init__(self, parent_type, relation, *args, **kwargs):
        super(QAddRelationDropdown, self).__init__(*args, **kwargs)
        self.relation = relation
        self.parent_widget = kwargs.get('parent')
        self.parent_type = parent_type
        self.cls = self.relation[1].mapper.class_
        self.has_secondary = bool(self.relation[1].secondary is not None)
        self.requires_relation = bool(self.relation[1].info.get('nullable') is False)
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.container = QWidget()
        self.container.setObjectName('container')
        self.container.setLayout(QHBoxLayout())
        self.container.layout().setContentsMargins(0, 0, 0, 0)
        if self.has_secondary:
            self.cb = QgsCheckableComboBox()
            if self.requires_relation:
                self.cb.checkedItemsChanged.connect(lambda items: self.setInvalid(not bool(items)))
            self.cb.view().customContextMenuRequested.disconnect()
        else:
            self.cb = QComboBoxNoScroll(self.parent_widget)
        self.cb.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        self.cb.setMinimumContentsLength(20)
        self.cb.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon)
        self.container.layout().addWidget(self.cb)
        self.layout.addWidget(self.container)
        self.refreshComboBox()
        if not issubclass(self.cls, CodeListValue):
            self.plus_icon_path = os.path.abspath(os.path.join(BASE_DIR, 'gui/resources/plus.svg'))
            self.b_plus = QToolButton()
            self.b_plus.setIcon(load_svg(self.plus_icon_path))
            self.b_plus.installEventFilter(self)
            self.b_plus.setCursor(Qt.CursorShape.PointingHandCursor)
            self.b_plus.setToolTip('Neues Objekt hinzufügen')
            self.b_plus.clicked.connect(self.addRelation)
            self.b_plus.setStyleSheet('\n                QToolButton {\n                    background: palette(window); \n                    border: 0px; \n                }\n                ')
            self.layout.addWidget(self.b_plus)
        self.cb.view().setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.cb.view().customContextMenuRequested.connect(self.onContextMenuRequested)
        self.setLayout(self.layout)

    def onContextMenuRequested(self, point):
        index = self.cb.view().indexAt(point)
        if not index.isValid():
            return
        data = self.cb.model().data(index, Qt.ItemDataRole.UserRole)
        if not data:
            return
        menu = QMenu()
        edit_action = QAction(QIcon(':/images/themes/default/mActionMultiEdit.svg'), 'Bearbeiten')
        edit_action.triggered.connect(lambda s, item_data=data: self.onEditObject(item_data))
        menu.addAction(edit_action)
        delete_action = QAction(QIcon(os.path.join(BASE_DIR, 'gui/resources/delete.svg')), 'Löschen')
        delete_action.triggered.connect(lambda s, item_data=data: self.onDeleteObject(item_data))
        menu.addAction(delete_action)
        menu.exec(self.cb.view().viewport().mapToGlobal(point))

    def onEditObject(self, item_xid):
        from SAGisXPlanung.gui.XPEditObjectDialog import XPEditObjectDialog
        xplan_item = XPlanungItem(xtype=self.cls, xid=item_xid)
        d = XPEditObjectDialog(xplan_item)
        result = d.exec()
        if result == QDialog.DialogCode.Accepted:
            self.refreshComboBox()

    def onDeleteObject(self, item_xid):
        with Session.begin() as session:
            obj_from_db = session.get(self.cls, item_xid)
            if not confirmObjectDeletion(obj_from_db):
                return
            session.delete(obj_from_db)
        self.refreshComboBox()

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Type.HoverEnter:
            obj.setIcon(load_svg(obj.icon().pixmap(obj.icon().actualSize(QSize(32, 32))), color='#1F2937'))
        elif event.type() == QEvent.Type.HoverLeave:
            obj.setIcon(load_svg(obj.icon().pixmap(obj.icon().actualSize(QSize(32, 32))), color='#6B7280'))
        return False

    @pyqtSlot()
    def addRelation(self):
        from SAGisXPlanung.gui.XPCreatePlanDialog import XPCreatePlanDialog
        d = XPCreatePlanDialog(iface=iface, cls_type=self.cls, parent_type=self.parent_type.cls_type)
        d.contentSaved.connect(self.refreshComboBox)
        d.exec()

    def refreshComboBox(self):
        self.cb.clear()
        if not isinstance(self.cb, QgsCheckableComboBox):
            self.cb.addItem('')
        with Session.begin() as session:
            for r in session.query(self.cls).all():
                self.cb.addItem(str(r), str(r.id))
        self.cb.model().sort(0)

    def validate_widget(self, required):
        if not self.has_secondary or not self.requires_relation:
            return True
        if not self.cb.checkedItems():
            self.setInvalid(True)
            return False
        self.setInvalid(False)
        return True

    def setInvalid(self, is_invalid):
        if not is_invalid:
            self.container.setStyleSheet('')
            self.container.layout().setContentsMargins(0, 0, 0, 0)
            return
        self.container.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
        self.container.layout().setContentsMargins(5, 5, 5, 5)
        self.container.setStyleSheet('#container {background-color: #ffb0b0; border: 1px solid red; border-radius: 3px;}')

    def value(self):
        values = []
        if not isinstance(self.cb, QgsCheckableComboBox):
            if (selected_id := self.cb.currentData()) is None:
                return
            with Session.begin() as session:
                session.expire_on_commit = False
                return session.get(self.cls, selected_id)
        user_data = self.cb.checkedItemsData()
        with Session.begin() as session:
            session.expire_on_commit = False
            for i, item in enumerate(self.cb.checkedItems()):
                values.append(session.get(self.cls, user_data[i]))
        return values

    def setDefault(self, default):
        if isinstance(self.cb, QgsCheckableComboBox):
            self.cb.setCheckedItems([str(o) for o in default])
        else:
            index = self.cb.findData(str(default.id))
            self.cb.setCurrentIndex(index)