# [SKRIP 7.2: Ringkasan per KPH sebagai tugas latar belakang (QgsTask)]
# Penulis: Badar Mubarok Yogaswara
# Pola: pekerjaan berat di fungsi tugas (latar belakang); proyek dan tabel di fungsi selesai (utama).
import csv
import os
import processing
from qgis.core import (QgsApplication, QgsTask, QgsMessageLog, Qgis, QgsProject,
                       QgsVectorLayer, QgsRasterLayer)

DATA = "D:/Latihan/paket-i4"
HASIL = "D:/Latihan/hasil_i4"
os.makedirs(HASIL, exist_ok=True)
SEMENTARA = "TEMPORARY_OUTPUT"


def jalankan(alat, **parameter):
    return processing.run(alat, parameter)["OUTPUT"]


def hitung_ringkasan(task, data, hasil):
    """Latar belakang. Hanya membaca berkas dan menjalankan alat; tidak menyentuh QgsProject."""
    batas = QgsVectorLayer(data + "/Batas_KPH.gpkg", "Batas_KPH", "ogr")
    sungai = QgsVectorLayer(data + "/Sungai.gpkg", "Sungai", "ogr")
    hotspot = QgsVectorLayer(data + "/Hotspot_Nasional.gpkg", "Hotspot_Nasional", "ogr")
    citra = QgsRasterLayer(data + "/Citra_KPH.tif", "Citra_KPH", "gdal")
    dsm = QgsRasterLayer(data + "/DSM_Drone.tif", "DSM", "gdal")
    dtm = QgsRasterLayer(data + "/DTM_Drone.tif", "DTM", "gdal")
    for lyr in (batas, sungai, hotspot, citra, dsm, dtm):
        if not lyr.isValid():
            raise ValueError("Layer tidak terbaca: " + lyr.name())

    # tahap 1 (0-25%): sempadan sungai
    sem = jalankan("native:buffer", INPUT=sungai, DISTANCE=30, DISSOLVE=True, OUTPUT=SEMENTARA)
    iris = jalankan("native:intersection", INPUT=batas, OVERLAY=sem, INPUT_FIELDS=["NAMA_KPH"],
                    OVERLAY_FIELDS=[], OUTPUT=SEMENTARA)
    sem_ha = {}
    for f in iris.getFeatures():
        sem_ha[f["NAMA_KPH"]] = sem_ha.get(f["NAMA_KPH"], 0) + f.geometry().area() / 10000
    task.setProgress(25)
    if task.isCanceled():
        return None

    # tahap 2 (25-50%): titik panas
    hit = jalankan("native:countpointsinpolygon", POLYGONS=batas, POINTS=hotspot, FIELD="HOTSPOT",
                   OUTPUT=SEMENTARA)
    titik = {f["NAMA_KPH"]: f["HOTSPOT"] for f in hit.getFeatures()}
    task.setProgress(50)
    if task.isCanceled():
        return None

    # tahap 3 (50-100%): raster
    ndvi = jalankan("native:rastercalc", LAYERS=[citra], OUTPUT=hasil + "/NDVI_KPH.tif",
                    EXPRESSION='("Citra_KPH@4" - "Citra_KPH@1") / ("Citra_KPH@4" + "Citra_KPH@1")')
    chm = jalankan("native:rastercalc", LAYERS=[dsm, dtm], OUTPUT=hasil + "/CHM.tif",
                   EXPRESSION='"DSM@1" - "DTM@1"')
    task.setProgress(75)

    def rata(jalur, awalan):
        raster = QgsRasterLayer(jalur, "r", "gdal")
        z = jalankan("native:zonalstatisticsfb", INPUT=batas, INPUT_RASTER=raster, RASTER_BAND=1,
                     COLUMN_PREFIX=awalan, STATISTICS=[2], OUTPUT=SEMENTARA)
        return {f["NAMA_KPH"]: f[awalan + "mean"] for f in z.getFeatures()}

    n, c = rata(ndvi, "n_"), rata(chm, "c_")
    task.setProgress(100)
    hasil_baris = []
    for f in batas.getFeatures():
        k = f["NAMA_KPH"]
        hasil_baris.append([k, round(f.geometry().area() / 10000, 2), round(sem_ha.get(k, 0), 2),
                            titik[k], round(n[k], 3), round(c[k], 2)])
    return hasil_baris


def selesai(exception, baris=None):
    """Program utama. Aman menyentuh proyek, tabel, dan tampilan."""
    if exception is not None:
        QgsMessageLog.logMessage("Ringkasan gagal: %s" % exception, "Ringkasan KPH", Qgis.Critical)
        return
    if baris is None:
        QgsMessageLog.logMessage("Ringkasan dibatalkan", "Ringkasan KPH", Qgis.Warning)
        return
    with open(HASIL + "/ringkasan_latar.csv", "w", newline="", encoding="utf-8") as f:
        w = csv.writer(f)
        w.writerow(["NAMA_KPH", "LUAS_HA", "SEMPADAN_HA", "HOTSPOT", "NDVI_RATA", "CHM_RATA_M"])
        w.writerows(baris)
    for nama in ("NDVI_KPH", "CHM"):
        QgsProject.instance().addMapLayer(QgsRasterLayer(HASIL + "/" + nama + ".tif", nama, "gdal"))
    for b in baris:
        print("%-10s luas %5.2f ha | sempadan %4.2f ha | titik panas %d | NDVI %.3f | CHM %.2f m"
              % tuple(b))
    QgsMessageLog.logMessage("Ringkasan selesai: %d KPH" % len(baris), "Ringkasan KPH", Qgis.Success)


tugas = QgsTask.fromFunction("Ringkasan per KPH", hitung_ringkasan, on_finished=selesai,
                             data=DATA, hasil=HASIL)
QgsApplication.taskManager().addTask(tugas)
print("Tugas berjalan di latar belakang; QGIS tetap bisa dipakai.")
