# -*- coding: utf-8 -*-
"""
split_multipart_tool.py — LVT4U

Core algorithm: split selected multipart features into singlepart features.

Algorithm learned from the open-source 'splitmultipart' QGIS plugin
by Alexandre Neto <senhor.neto@gmail.com> (GPL v2, 2013-2026).
This implementation is written from scratch to fit LVT4U architecture:
  - No standalone dialog: runs inline and reports via iface.messageBar()
  - Accepts the active layer directly (no internal canvas tracking)
  - Returns (n_split, n_new) for the caller to handle UI feedback
"""

from qgis.core import (
    Qgis,
    QgsVectorLayer,
    QgsVectorLayerUtils,
)
from qgis.PyQt.QtCore import QCoreApplication


def tr(text: str) -> str:
    """Translate text via Qt translation system."""
    return QCoreApplication.translate("SplitMultipart", text)


def split_multipart_features(layer: QgsVectorLayer) -> tuple[int, int]:
    """Split all selected multipart features on *layer* into singlepart features.

    Each part inherits the full attribute set of the original feature.
    The original feature keeps its FID and is updated to hold only part[0].
    Parts [1..N] are inserted as new features (new FIDs assigned by the layer).

    Each single-part geometry is converted to its multitype equivalent before
    insertion so that layers backed by Spatialite / PostGIS do not reject it.

    Args:
        layer: An editable QgsVectorLayer with at least one selected feature.

    Returns:
        Tuple (n_split_feats, n_new_feats) where:
            n_split_feats — number of multipart features that were split
            n_new_feats   — number of NEW features created (total output
                            features = n_split_feats + n_new_feats)

    Raises:
        Nothing — all exceptions are caught internally and surfaced as 0/0.
    """
    n_split_feats = 0
    n_new_feats = 0

    layer.beginEditCommand(tr("Split multipart features"))

    try:
        for feature in layer.selectedFeatures():
            geom = feature.geometry()
            if geom is None or not geom.isMultipart():
                continue  # skip singlepart or null geometry

            n_split_feats += 1
            parts = geom.asGeometryCollection()

            # Convert each part to multitype to prevent type-mismatch errors
            # in Spatialite / PostGIS layers (mirrors original plugin's fix)
            for part in parts:
                part.convertToMultiType()

            # Build attribute dict {field_index: value} for new features
            attributes = {i: v for i, v in enumerate(feature.attributes())}

            # --- Update original feature: keep FID, replace geom with part[0] ---
            feature.setGeometry(parts[0])
            layer.updateFeature(feature)

            # --- Insert new features for parts[1..N] ---
            for i in range(1, len(parts)):
                new_feat = QgsVectorLayerUtils.createFeature(
                    layer,
                    parts[i],
                    attributes,
                )
                layer.addFeature(new_feat)
                n_new_feats += 1

    except Exception:  # noqa: BLE001 — broad catch intentional for undo safety
        layer.destroyEditCommand()
        return 0, 0

    if n_new_feats > 0:
        layer.endEditCommand()
    else:
        layer.destroyEditCommand()  # nothing happened → don't dirty the undo stack

    return n_split_feats, n_new_feats


class SplitMultipartTool:
    """Thin wrapper that calls split_multipart_features() and pushes
    a result message to the QGIS message bar.

    Usage (from lvt_plugin.py handler)::

        tool = SplitMultipartTool(self.iface)
        tool.run()
    """

    PLUGIN_TAG = "LVT4U — Split Multipart"

    def __init__(self, iface):
        self.iface = iface

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def run(self) -> None:
        """Validate active layer state, run split, report result."""
        layer = self.iface.activeLayer()

        # ── Guard: must be a vector layer ──────────────────────────────
        if not isinstance(layer, QgsVectorLayer):
            self._warn(tr("No vector layer is active. Please select a layer."))
            return

        # ── Guard: must be in edit mode ────────────────────────────────
        if not layer.isEditable():
            self._warn(
                tr("Layer «{name}» is not in edit mode. "
                   "Enable editing first.").format(name=layer.name())
            )
            return

        # ── Guard: must have a selection ───────────────────────────────
        if layer.selectedFeatureCount() == 0:
            self._warn(tr("No features selected. Select multipart features first."))
            return

        # ── Run split ──────────────────────────────────────────────────
        n_split, n_new = split_multipart_features(layer)

        # ── Report result ──────────────────────────────────────────────
        if n_new > 0:
            total_out = n_split + n_new
            self._info(
                tr("Split {n_split} multipart feature(s) → {total} singlepart "
                   "feature(s) created.").format(
                    n_split=n_split,
                    total=total_out,
                )
            )
        else:
            self._warn(
                tr("No multipart features found in the current selection.")
            )

    # ------------------------------------------------------------------
    # Private helpers
    # ------------------------------------------------------------------

    def _info(self, message: str, duration: int = 8) -> None:
        self.iface.messageBar().pushMessage(
            self.PLUGIN_TAG,
            message,
            level=Qgis.MessageLevel.Success,
            duration=duration,
        )

    def _warn(self, message: str, duration: int = 8) -> None:
        self.iface.messageBar().pushMessage(
            self.PLUGIN_TAG,
            message,
            level=Qgis.MessageLevel.Warning,
            duration=duration,
        )
