# -*- coding: utf-8 -*-
"""Overlap checker using R-Tree spatial index.

Detects ANY polygon intersection (overlaps, contains, within)
using intersects() + area check instead of just overlaps().

Author: Loc Vu Trung tong hop vi dam me cung ban!
"""
from .base import BaseChecker


class OverlapChecker(BaseChecker):
    name = "overlaps"
    display_name_en = "Overlaps"
    display_name_vi = "Chong de (Overlaps)"

    def check(self, layer, params):
        from qgis.core import QgsSpatialIndex
        index = QgsSpatialIndex(layer.getFeatures())
        features = {f.id(): f for f in layer.getFeatures()}
        overlaps, checked = [], set()

        for fid, feat in features.items():
            g1 = feat.geometry()
            if not g1 or g1.isNull():
                continue
            for cid in index.intersects(g1.boundingBox()):
                if cid <= fid:
                    continue
                pair = (fid, cid)
                if pair in checked:
                    continue
                checked.add(pair)
                g2 = features[cid].geometry()
                if not g2 or g2.isNull():
                    continue
                # Use intersects() instead of overlaps() to catch ALL cases:
                # overlaps, contains, within, crosses
                if not g1.intersects(g2):
                    continue
                # Skip touching-only (shared boundary but no area)
                if g1.touches(g2):
                    continue
                inter = g1.intersection(g2)
                if inter and not inter.isNull() and inter.area() > 0:
                    overlaps.append(inter)
        return {"error_geometries": overlaps, "error_features": [],
                "details": [f"Area: {g.area():.4f} m2" for g in overlaps]}

    def fix(self, input_path, output_path, params):
        from qgis.core import (
            QgsVectorLayer, QgsSpatialIndex,
            QgsVectorFileWriter, QgsCoordinateTransformContext)
        # Use same threshold as must_not_overlap for consistency
        min_area = params.get("mno_min_area", 0.001)
        layer = QgsVectorLayer(input_path, "in", "ogr")
        features = {f.id(): f for f in layer.getFeatures()}
        index = QgsSpatialIndex(layer.getFeatures())
        changes = {}
        checked = set()

        for fid, feat in features.items():
            g1 = changes.get(fid, feat.geometry())
            if not g1 or g1.isNull():
                continue
            for cid in index.intersects(g1.boundingBox()):
                if cid <= fid:
                    continue
                if (fid, cid) in checked:
                    continue
                checked.add((fid, cid))
                g2 = changes.get(cid, features[cid].geometry())
                if not g2 or g2.isNull():
                    continue
                if not g1.intersects(g2) or g1.touches(g2):
                    continue
                inter = g1.intersection(g2)
                if not inter or inter.isNull() or inter.area() <= min_area:
                    continue
                # Cut overlap from feature with SMALLER area
                if g1.area() <= g2.area():
                    orig_area = g1.area()
                    result = g1.difference(inter)
                    # Safety guards
                    if not result or result.isNull() or result.isEmpty():
                        continue
                    if result.area() < orig_area * 0.5:
                        continue
                    if not result.isGeosValid():
                        result = result.makeValid()
                        if not result or result.isNull():
                            continue
                    g1 = result
                    changes[fid] = g1
                else:
                    orig_area = g2.area()
                    result = g2.difference(inter)
                    # Safety guards
                    if not result or result.isNull() or result.isEmpty():
                        continue
                    if result.area() < orig_area * 0.5:
                        continue
                    if not result.isGeosValid():
                        result = result.makeValid()
                        if not result or result.isNull():
                            continue
                    g2 = result
                    changes[cid] = g2

        if changes:
            layer.dataProvider().changeGeometryValues(changes)

        opts = QgsVectorFileWriter.SaveVectorOptions()
        opts.driverName = "GPKG"
        opts.forceMulti = True
        opts.includeZ = True
        QgsVectorFileWriter.writeAsVectorFormatV3(
            layer, output_path, QgsCoordinateTransformContext(), opts)
        return output_path
