from qgis.core import edit


def calculate_area_value(geom):
    if geom is None or geom.isEmpty():
        return "0.00"

    try:
        area = round(float(geom.area()), 2)
    except Exception:
        area = 0.0

    return f"{area:.2f}"


def update_area_for_feature(layer, fid):
    if layer is None or not layer.isValid():
        return False

    area_idx = layer.fields().indexOf("AREA")
    if area_idx < 0:
        return False

    feature = layer.getFeature(fid)
    if not feature.isValid():
        return False

    geom = feature.geometry()
    area_value = calculate_area_value(geom)

    if layer.isEditable():
        return layer.changeAttributeValue(fid, area_idx, area_value)

    try:
        with edit(layer):
            return layer.changeAttributeValue(fid, area_idx, area_value)
    except Exception:
        return False


def update_area_for_all_features(layer):
    if layer is None or not layer.isValid():
        return False

    area_idx = layer.fields().indexOf("AREA")
    if area_idx < 0:
        return False

    started_here = False

    if not layer.isEditable():
        if not layer.startEditing():
            return False
        started_here = True

    ok_all = True

    for feat in layer.getFeatures():
        geom = feat.geometry()
        area_value = calculate_area_value(geom)
        ok = layer.changeAttributeValue(feat.id(), area_idx, area_value)
        if not ok:
            ok_all = False

    if started_here:
        if not layer.commitChanges():
            return False

    return ok_all


class ManagedFieldsController:
    """
    Kontrollon fushat e menaxhuara automatikisht.
    Aktualisht:
      - AREA për PARC_TRANS
      - AREA për BUILDINGS_TRANS
    """

    def __init__(self):
        self.layers = []
        self.connected_ids = set()

    def attach_layer(self, layer):
        if layer is None or not layer.isValid():
            return

        layer_id = layer.id()
        if layer_id in self.connected_ids:
            return

        # Rikalkulim fillestar
        update_area_for_all_features(layer)

        # Kur ndryshon gjeometria
        layer.geometryChanged.connect(
            lambda fid, geom, lyr=layer: self._on_geometry_changed(lyr, fid)
        )

        # Kur shtohet feature i ri
        layer.featureAdded.connect(
            lambda fid, lyr=layer: self._on_feature_added(lyr, fid)
        )

        # Para commit
        # Përdorim *args që të mos na prishet nga nënshkrimi i sinjalit në versione të ndryshme të QGIS
        layer.beforeCommitChanges.connect(
            lambda *args, lyr=layer: self._on_before_commit(lyr)
        )

        self.layers.append(layer)
        self.connected_ids.add(layer_id)

    def attach_layers(self, parcels_layer, buildings_layer):
        self.attach_layer(parcels_layer)
        self.attach_layer(buildings_layer)

    def _on_geometry_changed(self, layer, fid):
        update_area_for_feature(layer, fid)

    def _on_feature_added(self, layer, fid):
        update_area_for_feature(layer, fid)

    def _on_before_commit(self, layer):
        update_area_for_all_features(layer)