# Skrip 4.6 (Bab Jembatan): proyek mini terpadu B1-B4 dan pembuka geoprocessing.
# Alur: periksa CRS, reproject titik panas, seleksi atribut, buffer sungai, clip, simbologi, layout, ekspor.
import os
import processing
from qgis.core import (QgsProject, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFillSymbol,
                       QgsSingleSymbolRenderer, QgsMarkerSymbol, QgsLineSymbol, QgsPrintLayout,
                       QgsLayoutItemMap, QgsLayoutItemLabel, QgsLayoutItemLegend, QgsLayoutItemScaleBar,
                       QgsLayoutPoint, QgsLayoutSize, QgsLayoutExporter, QgsRectangle, QgsTextFormat, Qgis)
from qgis.PyQt.QtGui import QFont

FOLDER = r"D:/KPH_Contoh"   # ganti dengan folder kerja Anda
JARAK_SEMPADAN = 25         # meter; angka latihan, bukan ketentuan resmi

proyek = QgsProject.instance()
proyek.clear()
proyek.setCrs(QgsCoordinateReferenceSystem("EPSG:32749"))

def muat(berkas, lapisan, nama):
    layer = QgsVectorLayer("%s/%s|layername=%s" % (FOLDER, berkas, lapisan), nama, "ogr")
    assert layer.isValid(), "Layer tidak terbaca: " + nama
    return layer

# 1. Periksa CRS: titik panas kiriman kantor lain masih berderajat (B1)
mentah = muat("Hotspot_derajat.gpkg", "Hotspot_derajat", "Hotspot_mentah")
print("CRS titik panas mentah:", mentah.crs().authid(), "| satuan:", mentah.crs().mapUnits())

# 2. Reproject ke UTM 49S (alat Processing pertama)
hasil = processing.run("native:reprojectlayer", {
    "INPUT": mentah, "TARGET_CRS": QgsCoordinateReferenceSystem("EPSG:32749"), "OUTPUT": "memory:Titik_Panas"})
titik = hasil["OUTPUT"]
print("Titik panas setelah reproject:", titik.featureCount(), "titik,", titik.crs().authid())

# 3. Data utama
petak = muat("Petak_KPH.gpkg", "Petak_KPH", "Petak KPH")
sungai = muat("Sungai_Jalan.gpkg", "Sungai", "Sungai")

# 4. Seleksi atribut (B2): petak jati bervolume tinggi
petak.selectByExpression('"Jenis" = \'Jati\' AND "Volume_m3ha" > 150')
print("Jati dengan volume > 150 m3/ha:", sorted(f["ID_Petak"] for f in petak.selectedFeatures()))
petak.removeSelection()

# 5. Buffer sungai (alat Processing kedua): sempadan contoh 25 m, digabung jadi satu bidang
sempadan = processing.run("native:buffer", {
    "INPUT": sungai, "DISTANCE": JARAK_SEMPADAN, "SEGMENTS": 16, "DISSOLVE": True,
    "OUTPUT": "memory:Sempadan"})["OUTPUT"]
luas_sempadan = sum(f.geometry().area() for f in sempadan.getFeatures())
print("Luas buffer sungai: %.0f m2 (%.2f ha)" % (luas_sempadan, luas_sempadan / 10000))

# 6. Clip petak dengan buffer: bagian petak yang masuk sempadan
petak_sempadan = processing.run("native:clip", {
    "INPUT": petak, "OVERLAY": sempadan, "OUTPUT": "memory:Petak_di_sempadan"})["OUTPUT"]
total = 0
for f in sorted(petak_sempadan.getFeatures(), key=lambda x: x["ID_Petak"]):
    luas = f.geometry().area()
    total += luas
    print("   %s  %-6s %7.0f m2" % (f["ID_Petak"], f["Jenis"], luas))
print("Total petak dalam sempadan: %.0f m2 (%.2f ha), %d petak" % (total, total / 10000, petak_sempadan.featureCount()))

# 7. Clip titik panas dengan buffer: titik panas yang berada di dalam sempadan
titik_dalam = processing.run("native:clip", {
    "INPUT": titik, "OVERLAY": sempadan, "OUTPUT": "memory:Titik_di_sempadan"})["OUTPUT"]
print("Titik panas di dalam sempadan:", titik_dalam.featureCount(), "dari", titik.featureCount())

# 8. Simbologi (B4) dan penyusunan layer; urutan: yang ditambah belakangan berada di atas
petak.setRenderer(QgsSingleSymbolRenderer(QgsFillSymbol.createSimple(
    {"color": "#E8F0D8", "outline_color": "#404040", "outline_width": "0.3"})))
sempadan.setRenderer(QgsSingleSymbolRenderer(QgsFillSymbol.createSimple(
    {"color": "#8FB8E0", "outline_color": "#2B6CB0", "outline_width": "0.2", "style": "solid"})))
petak_sempadan.setRenderer(QgsSingleSymbolRenderer(QgsFillSymbol.createSimple(
    {"color": "#F2A65A", "outline_color": "#8A4B00", "outline_width": "0.3"})))
sungai.setRenderer(QgsSingleSymbolRenderer(QgsLineSymbol.createSimple({"line_color": "#2B6CB0", "line_width": "0.8"})))
titik.setRenderer(QgsSingleSymbolRenderer(QgsMarkerSymbol.createSimple(
    {"name": "circle", "color": "#E03C31", "outline_color": "#FFFFFF", "size": "2.6"})))
for layer in (petak, sempadan, petak_sempadan, sungai, titik):
    proyek.addMapLayer(layer)
petak_sempadan.setName("Petak di dalam sempadan")
sempadan.setName("Sempadan sungai %g m" % JARAK_SEMPADAN)
titik.setName("Titik panas")

# 9. Layout ringkas dan ekspor
mm = Qgis.LayoutUnit.Millimeters
tata = QgsPrintLayout(proyek)
tata.initializeDefaults()
tata.setName("Peta_Sempadan")
proyek.layoutManager().addLayout(tata)
peta = QgsLayoutItemMap(tata)
peta.setCrs(proyek.crs())
peta.attemptMove(QgsLayoutPoint(10, 28, mm))
peta.attemptResize(QgsLayoutSize(190, 140, mm))
peta.zoomToExtent(QgsRectangle(312000, 9996000, 312400, 9996400))
peta.setScale(3000)
peta.setFrameEnabled(True)
tata.addLayoutItem(peta)
judul = QgsLayoutItemLabel(tata)
judul.setText("SEMPADAN SUNGAI DI KPH CONTOH (CONTOH %g M)" % JARAK_SEMPADAN)
fmt = QgsTextFormat()
fmt.setFont(QFont("Arial", 16, QFont.Weight.Bold))
fmt.setSize(16)
judul.setTextFormat(fmt)
judul.attemptMove(QgsLayoutPoint(10, 10, mm))
judul.attemptResize(QgsLayoutSize(277, 12, mm))
tata.addLayoutItem(judul)
legenda = QgsLayoutItemLegend(tata)
legenda.setLinkedMap(peta)
legenda.setTitle("Legenda")
legenda.attemptMove(QgsLayoutPoint(205, 28, mm))
tata.addLayoutItem(legenda)
skala = QgsLayoutItemScaleBar(tata)
skala.setLinkedMap(peta)
skala.setStyle("Single Box")
skala.setUnits(Qgis.DistanceUnit.Meters)
skala.setUnitLabel("m")
skala.setNumberOfSegments(2)
skala.setNumberOfSegmentsLeft(0)
skala.setUnitsPerSegment(100)
skala.attemptMove(QgsLayoutPoint(12, 174, mm))
tata.addLayoutItem(skala)
hasil_pdf = QgsLayoutExporter(tata).exportToPdf(os.path.join(FOLDER, "Peta_Sempadan.pdf"), QgsLayoutExporter.PdfExportSettings())
print("Ekspor PDF:", hasil_pdf, "(0 = berhasil)")
proyek.write(os.path.join(FOLDER, "KPH_Contoh_B4.qgz"))
print("Proyek disimpan:", os.path.exists(os.path.join(FOLDER, "KPH_Contoh_B4.qgz")))
