# Skrip 4.1: memeriksa dan memperbaiki galat topologi dasar pada Petak_Rusak (QGIS Python Console)
# Penulis: Badar Mubarok Yogaswara
import os
import processing
from qgis.core import QgsVectorLayer, QgsWkbTypes

DATA = os.environ.get("B2_DATA", r"C:/KPH_Contoh/paket-b2")
KELUAR = os.environ.get("B2_KELUAR", r"C:/KPH_Contoh/keluaran")
os.makedirs(KELUAR, exist_ok=True)
rusak = QgsVectorLayer(DATA + "/Petak_Rusak.gpkg|layername=Petak_Rusak", "Petak_Rusak", "ogr")
print("Jumlah objek Petak_Rusak:", rusak.featureCount())


def jalankan(alg, **param):
    return processing.run(alg, param)


# 1. Geometri tidak sah (mis. garis menyilang sendiri)
v = jalankan("native:checkvalidity", INPUT_LAYER=rusak, METHOD=2,
             VALID_OUTPUT="memory:", INVALID_OUTPUT="memory:", ERROR_OUTPUT="memory:")
print("Sah:", v["VALID_COUNT"], "| Tidak sah:", v["INVALID_COUNT"], "| Titik galat:", v["ERROR_COUNT"])
for f in v["INVALID_OUTPUT"].getFeatures():
    print("   tidak sah:", f["KODE_PETAK"], "|", f["_errors"])

# 2. Perbaiki geometri tidak sah lebih dulu (alat pemeriksa lain menolak geometri rusak)
perbaiki = jalankan("native:fixgeometries", INPUT=rusak, METHOD=1, OUTPUT="memory:")
fix = perbaiki["OUTPUT"]
print("Setelah perbaiki geometri:", fix.featureCount(), "objek")
v2 = jalankan("native:checkvalidity", INPUT_LAYER=fix, METHOD=2,
              VALID_OUTPUT="memory:", INVALID_OUTPUT="memory:", ERROR_OUTPUT="memory:")
print("Ulang cek: sah", v2["VALID_COUNT"], "| tidak sah", v2["INVALID_COUNT"])
for f in fix.getFeatures():
    if f["KODE_PETAK"] == "P-18":
        print("   P-18 setelah perbaikan:", QgsWkbTypes.displayString(f.geometry().wkbType()), "| luas m2:", round(f.geometry().area(), 1))

# 3. Duplikat
d = jalankan("native:checkgeometryduplicate", INPUT=fix, UNIQUE_ID="fid", ERRORS="memory:")
print("Galat duplikat:", d["ERRORS"].featureCount())

# 4. Tumpang tindih (overlap) dan celah (gap)
o = jalankan("native:checkgeometryoverlap", INPUT=fix, UNIQUE_ID="fid", MIN_OVERLAP_AREA=0, ERRORS="memory:")
print("Galat tumpang tindih:", o["ERRORS"].featureCount())
print("   kolom:", [x.name() for x in o["ERRORS"].fields()])
for f in o["ERRORS"].getFeatures():
    print("   ", f.attributes()[1:])
g = jalankan("native:checkgeometrygap", INPUT=fix, UNIQUE_ID="fid", GAP_THRESHOLD=5000,
             NEIGHBORS="memory:", ERRORS="memory:", OUTPUT="memory:")
print("Galat celah:", g["ERRORS"].featureCount())
print("   kolom:", [x.name() for x in g["ERRORS"].fields()])
for f in g["ERRORS"].getFeatures():
    print("   ", f.attributes()[1:])

# 5. Perbaikan duplikat
bersih = jalankan("native:deleteduplicategeometries", INPUT=fix, OUTPUT="memory:", DUPLICATES="memory:")
print("Setelah hapus duplikat:", bersih["OUTPUT"].featureCount(), "objek | duplikat dibuang:", bersih["DUPLICATE_COUNT"])

# 6. Perbaiki tumpang tindih (alat "Delete overlaps") pada lapisan yang sudah bebas duplikat
bersih_l = bersih["OUTPUT"]
o2 = jalankan("native:checkgeometryoverlap", INPUT=bersih_l, UNIQUE_ID="fid", MIN_OVERLAP_AREA=0, ERRORS="memory:")
tanpa_tumpang = jalankan("native:fixgeometryoverlap", INPUT=bersih_l, ERRORS=o2["ERRORS"], UNIQUE_ID="fid",
                         OVERLAP_FEATURE_UNIQUE_IDX="gc_overlap_feature_fid", ERROR_VALUE_ID="gc_error",
                         OUTPUT="memory:", REPORT="memory:")["OUTPUT"]
o3 = jalankan("native:checkgeometryoverlap", INPUT=tanpa_tumpang, UNIQUE_ID="fid", MIN_OVERLAP_AREA=0, ERRORS="memory:")
print("Setelah Delete overlaps | objek:", tanpa_tumpang.featureCount(), "| tumpang tindih tersisa:", o3["ERRORS"].featureCount())
for f in tanpa_tumpang.getFeatures():
    if f["KODE_PETAK"] in ("P-06", "P-07"):
        print("   ", f["KODE_PETAK"], "luas m2:", round(f.geometry().area(), 1))
# Celah: alat "Fill gaps" dicoba pada data latihan dan melaporkan "Failed to merge with neighbor".
# Celah ini diperbaiki dengan tangan (Vertex Tool + snapping), seperti di Bab 4.
