# -*- coding: utf-8 -*-
# Penulis: Badar Mubarok Yogaswara. Dijalankan di Python Console QGIS. Data sintetis, bukan kondisi lapangan nyata.
from qgis.core import QgsVectorLayer, QgsProject, QgsProperty
import processing

PAKET = r"C:\latihan\paket-i1"      # ubah sesuai letak folder di komputer Anda
DATA = r"C:\latihan\paket-data"


def muat(berkas, lapisan, nama):
    """Memuat satu layer GeoPackage dan menambahkannya ke proyek."""
    lyr = QgsVectorLayer("%s|layername=%s" % (berkas, lapisan), nama, "ogr")
    if not lyr.isValid():
        raise RuntimeError("Layer tidak terbaca: " + berkas)
    QgsProject.instance().addMapLayer(lyr)
    return lyr


def luas_ha(lyr):
    """Jumlah luas semua poligon dalam hektare (CRS harus UTM, satuan meter)."""
    return sum(f.geometry().area() for f in lyr.getFeatures()) / 10000.0


def buf(lyr, jarak):
    """Buffer dengan dissolve, hasil sementara."""
    return processing.run("native:buffer", {"INPUT": lyr, "DISTANCE": jarak, "DISSOLVE": True, "OUTPUT": "memory:"})["OUTPUT"]


from collections import Counter

petak = muat(PAKET + r"\Petak.gpkg", "Petak", "Petak")
jalan = muat(PAKET + r"\Jalan.gpkg", "Jalan", "Jalan")
kph = muat(DATA + r"\Batas_KPH.gpkg", "Batas_KPH", "Batas_KPH")
titik = muat(DATA + r"\Hotspot_Nasional.gpkg", "Hotspot_Nasional", "Hotspot_Nasional")

# 1. Spatial join petak ke KPH. Predikat 0 = intersect, 5 = are within. Metode 0 = satu-ke-banyak
for nama, pred in (("intersect", 0), ("are within", 5)):
    j = processing.run("native:joinattributesbylocation", {"INPUT": petak, "PREDICATE": [pred], "JOIN": kph, "JOIN_FIELDS": ["NAMA_KPH"], "METHOD": 0, "OUTPUT": "memory:"})["OUTPUT"]
    print("Join dengan %-10s: %d baris (petak ada 16)" % (nama, j.featureCount()))

# 2. Join yang benar: 'are within', ambil satu (metode 1)
petak_kph = processing.run("native:joinattributesbylocation", {"INPUT": petak, "PREDICATE": [5], "JOIN": kph, "JOIN_FIELDS": ["NAMA_KPH"], "METHOD": 1, "OUTPUT": "memory:"})["OUTPUT"]
print("Petak per KPH:", dict(Counter(f["NAMA_KPH"] for f in petak_kph.getFeatures())))

# 3. Hitung titik panas per petak
hitung = processing.run("native:countpointsinpolygon", {"POLYGONS": petak_kph, "POINTS": titik, "FIELD": "JML_TITIK", "OUTPUT": "memory:"})["OUTPUT"]
per_petak = {f["KODE_PETAK"]: int(f["JML_TITIK"]) for f in hitung.getFeatures() if f["JML_TITIK"] > 0}
print("Titik per petak:", per_petak, "jumlah =", sum(per_petak.values()))
per_kph = Counter()
for f in hitung.getFeatures():
    per_kph[f["NAMA_KPH"]] += int(f["JML_TITIK"])
print("Titik per KPH:", dict(per_kph))

# 4. Ringkasan berdasarkan lokasi (join summary): hitung titik per petak
ringkas = processing.run("native:joinbylocationsummary", {"INPUT": petak, "PREDICATE": [0], "JOIN": titik, "JOIN_FIELDS": ["ID_Titik"], "SUMMARIES": [0], "DISCARD_NONMATCHING": False, "OUTPUT": "memory:"})["OUTPUT"]
kolom = ringkas.fields()[ringkas.fields().count() - 1].name()
print("Kolom hasil ringkasan:", kolom)
print("Total count:", int(sum((f[kolom] or 0) for f in ringkas.getFeatures())))

# 5. Select by location: petak yang beririsan dengan titik panas
processing.run("native:selectbylocation", {"INPUT": petak, "PREDICATE": [0], "INTERSECT": titik, "METHOD": 0})
print("Petak terpilih:", sorted(f["KODE_PETAK"] for f in petak.selectedFeatures()))
petak.removeSelection()

# 6. Jalan terdekat dari tiap titik panas
dekat = processing.run("native:joinbynearest", {"INPUT": titik, "INPUT_2": jalan, "FIELDS_TO_COPY": ["NAMA"], "NEIGHBORS": 1, "OUTPUT": "memory:"})["OUTPUT"]
baris = sorted((f["distance"], f["ID_Titik"], f["NAMA"]) for f in dekat.getFeatures())
print("Terdekat ke jalan: %s %.1f m (%s); terjauh: %s %.1f m" % (baris[0][1], baris[0][0], baris[0][2], baris[-1][1], baris[-1][0]))

# 7. Titik panas ke petak (are within, satu-ke-satu), lalu hitung titik per jenis
titik_petak = processing.run("native:joinattributesbylocation", {"INPUT": titik, "PREDICATE": [5], "JOIN": petak, "JOIN_FIELDS": ["KODE_PETAK", "JENIS"], "METHOD": 1, "OUTPUT": "memory:"})["OUTPUT"]
print("Titik di petak P07:", sorted(f["ID_Titik"] for f in titik_petak.getFeatures() if f["KODE_PETAK"] == "P07"))
per_jenis = {}
for f in titik_petak.getFeatures():
    per_jenis.setdefault(f["JENIS"], []).append(f["ID_Titik"])
for jenis, daftar in sorted(per_jenis.items()):
    print("Titik pada %-7s: %d %s" % (jenis, len(daftar), sorted(daftar)))
