from qgis.core import (QgsProject, QgsVectorLayer, QgsField, QgsMessageLog,
                       QgsWkbTypes, QgsSymbol, QgsRendererCategory,
                       QgsCategorizedSymbolRenderer)
from qgis.utils import iface
from qgis.PyQt.QtWidgets import QShortcut
from qgis.PyQt.QtGui import QKeySequence, QColor
from qgis.PyQt.QtCore import Qt
from .translations import get_text


try:
    from qgis.PyQt.QtCore import QMetaType

    INT_TYPE = QMetaType.Type.Int
    STRING_TYPE = QMetaType.Type.QString
except AttributeError:
    from qgis.PyQt.QtCore import QVariant

    INT_TYPE = QVariant.Int
    STRING_TYPE = QVariant.String


class TrackerEngine:
    def __init__(self):
        self.tracked_data = {}  # {layer_id: {'layer': QgsVectorLayer, 'field_idx': int}}
        self.shortcuts = []
        self.hotkey_settings = {}  # { '1': '1', '2': '0', ... }
        self.modified_value = 1
        self.language = "en"

    def set_language(self, language):
        self.language = language

    def configure_hotkeys(self, hotkey_dict):
        """挂载快捷键逻辑"""
        self._clear_shortcuts()
        self.hotkey_settings = hotkey_dict

        main_window = iface.mainWindow()
        # 兼容 Qt5/6 的上下文环境
        context = getattr(Qt, 'ApplicationShortcut', None)
        if context is None:
            context = Qt.ShortcutContext.ApplicationShortcut

        for key, val in hotkey_dict.items():
            sc = QShortcut(QKeySequence(key), main_window)
            sc.setContext(context)
            # 闭包绑定当前 key 的值
            sc.activated.connect(lambda v=val: self.apply_hotkey_override(v))
            self.shortcuts.append(sc)

    def _clear_shortcuts(self):
        for sc in self.shortcuts:
            sc.setEnabled(False)
            sc.deleteLater()
        self.shortcuts.clear()

    def start_tracking(self, layers, target_field):
        """批量启动图层追踪，处理字段异构"""
        if not target_field.strip():
            target_field = "al_checked"

        success_count = 0
        for layer in layers:
            field_name = target_field
            field_idx = layer.fields().indexOf(field_name)

            # 异构验证逻辑
            if field_idx != -1:
                f_type = layer.fields().at(field_idx).type()
                # 如果存在的字段不是数字也不是字符串（比如是日期或Blob），则降级使用 al_checked
                if f_type not in [INT_TYPE, STRING_TYPE]:
                    iface.messageBar().pushWarning(
                        get_text(self.language, "field_type_conflict_title"),
                        get_text(self.language, "field_type_conflict_message", layer=layer.name(), field=field_name)
                    )
                    field_name = "al_checked"
                    field_idx = layer.fields().indexOf(field_name)

            # 字段不存在时的创建逻辑
            if field_idx == -1:
                was_editing = layer.isEditable()
                if was_editing: layer.commitChanges()

                new_field = QgsField(field_name, INT_TYPE)
                layer.dataProvider().addAttributes([new_field])
                layer.updateFields()
                field_idx = layer.fields().indexOf(field_name)

                # 初始化为 0
                layer.startEditing()
                layer.beginEditCommand(get_text(self.language, "init_field_command", field=field_name))
                for f in layer.getFeatures():
                    layer.changeAttributeValue(f.id(), field_idx, 0)
                layer.endEditCommand()
                layer.commitChanges()

                if was_editing: layer.startEditing()

            # 显式绑定图层来源，避免依赖 activeLayer 猜测信号来源。
            layer_id = layer.id()
            cb_geom = lambda fid, geom, lid=layer_id: self._on_geometry_changed(lid, fid)
            cb_add = lambda fid, lid=layer_id: self._on_feature_added(lid, fid)
            layer.geometryChanged.connect(cb_geom)
            layer.featureAdded.connect(cb_add)
            self.tracked_data[layer_id] = {
                'layer': layer,
                'field_idx': field_idx,
                'cb_geom': cb_geom,
                'cb_add': cb_add
            }

            self._apply_categorized_symbology(layer, field_name)
            success_count += 1

        return success_count

    def stop_all(self):
        """全量释放资源（生命周期安全出口）"""
        for lid, data in self.tracked_data.items():
            layer = data['layer']
            try:
                layer.geometryChanged.disconnect(data['cb_geom'])
            except (TypeError, RuntimeError, KeyError):
                pass  # 图层已被销毁或信号已断开时安全忽略
            try:
                layer.featureAdded.disconnect(data['cb_add'])
            except (TypeError, RuntimeError):
                pass  # 图层已被销毁或信号已断开时安全忽略
        self.tracked_data.clear()
        self._clear_shortcuts()

    def remove_layer_tracking(self, layer_id):
        """当工程中图层被删除时安全剥离"""
        if layer_id in self.tracked_data:
            data = self.tracked_data.pop(layer_id)
            try:
                data['layer'].geometryChanged.disconnect(data['cb_geom'])
            except:
                pass
            try:
                data['layer'].featureAdded.disconnect(data['cb_add'])
            except:
                pass

    def _set_feature_modified(self, layer_id, fid):
        data = self.tracked_data.get(layer_id)
        if not data:
            return

        layer = data['layer']
        if not layer or not layer.isEditable():
            return

        layer.changeAttributeValue(fid, data['field_idx'], self.modified_value)
        layer.triggerRepaint()

    def _on_geometry_changed(self, layer_id, fid):
        """几何修改时自动将状态字段写为已修改。"""
        self._set_feature_modified(layer_id, fid)

    def _on_feature_added(self, layer_id, fid):
        """新建或切分产生的新要素时自动标记为已修改。"""
        self._set_feature_modified(layer_id, fid)

    def apply_hotkey_override(self, val_str):
        """快捷键覆写逻辑：严格归属于当前上下文"""
        active_layer = iface.activeLayer()

        # 规则 4: 未勾选追踪的激活图层，拒绝操作并弹出 Message
        if not active_layer or active_layer.id() not in self.tracked_data:
            iface.messageBar().pushInfo(
                get_text(self.language, "untracked_layer_title"),
                get_text(self.language, "untracked_layer_message")
            )
            return

        if not active_layer.isEditable():
            iface.messageBar().pushWarning(
                get_text(self.language, "layer_not_editable_title"),
                get_text(self.language, "layer_not_editable_message")
            )
            return

        selected_fids = active_layer.selectedFeatureIds()
        if not selected_fids:
            return

        f_idx = self.tracked_data[active_layer.id()]['field_idx']

        # 尝试转为数字，以适应整型字段
        try:
            val = int(val_str)
        except ValueError:
            val = val_str

        active_layer.beginEditCommand(get_text(self.language, "hotkey_edit_command", value=val))
        for fid in selected_fids:
            active_layer.changeAttributeValue(fid, f_idx, val)
        active_layer.endEditCommand()
        active_layer.triggerRepaint()

    def _apply_categorized_symbology(self, layer, field_name):
        """自动检测 Single Symbol 并转换为分类符号 (Categorized)"""
        # 1. 拦截：仅处理单一符号的图层
        if layer.renderer().type() != 'singleSymbol':
            return

        # 2. 提取需要创建分类的所有值 (去重)，确保至少有我们追踪的值
        tracked_values = set(self.hotkey_settings.values())
        tracked_values.add(str(self.modified_value))

        categories = []
        geom_type = layer.geometryType()

        # 兼容 Qt5/6 的无填充枚举 (用于面状数据透明)
        brush_style = getattr(Qt, 'BrushStyle', Qt)

        for val_str in tracked_values:
            # 尝试转为整型以匹配数据库类型
            try:
                val = int(val_str)
            except ValueError:
                val = val_str

            # 创建基于几何类型的默认符号
            symbol = QgsSymbol.defaultSymbol(geom_type)
            if not symbol:
                continue

            # 3. 颜色映射逻辑 (1=绿, 0=红, 其他=蓝色系作为备选)
            if val_str == '1':
                color = QColor(0, 255, 0)  # 纯绿
            elif val_str == '0':
                color = QColor(255, 0, 0)  # 纯红
            else:
                color = QColor(0, 150, 255)  # 其他值为亮蓝色

            # 4. 根据几何类型精细化样式
            if geom_type == QgsWkbTypes.PolygonGeometry:
                # 面要素：无填充，仅改变轮廓颜色，加粗轮廓
                layer_sym = symbol.symbolLayer(0)
                layer_sym.setBrushStyle(brush_style.NoBrush)
                layer_sym.setStrokeColor(color)
                layer_sym.setStrokeWidth(0.66)  # 稍微加粗让用户更容易看清
            else:
                # 点/线要素：直接改变主颜色
                symbol.setColor(color)
                if geom_type == QgsWkbTypes.LineGeometry:
                    symbol.symbolLayer(0).setWidth(0.66)

            # 创建该分类
            category = QgsRendererCategory(val, symbol, str(val))
            categories.append(category)

        # 5. 添加一个兜底的默认分类 (其他所有未匹配的值)
        default_symbol = QgsSymbol.defaultSymbol(geom_type)
        if geom_type == QgsWkbTypes.PolygonGeometry:
            default_symbol.symbolLayer(0).setBrushStyle(brush_style.NoBrush)
            default_symbol.symbolLayer(0).setStrokeColor(QColor(150, 150, 150))  # 灰色轮廓
        else:
            default_symbol.setColor(QColor(150, 150, 150))

        categories.append(QgsRendererCategory("", default_symbol, get_text(self.language, "other_unmarked")))

        # 6. 生成并应用分类渲染器
        renderer = QgsCategorizedSymbolRenderer(field_name, categories)
        layer.setRenderer(renderer)
        layer.triggerRepaint()