# -*- coding: utf-8 -*-
# [SKRIP I3.6] Pemeriksa kualitas data survei: kelengkapan, nilai baku, rentang, duplikat, letak, dan akurasi GNSS.
# Penulis: Badar Mubarok Yogaswara
# Dijalankan di Python Console QGIS atau python-qgis.bat. Hanya MEMBACA data; tidak mengubah apa pun.
from collections import Counter
from qgis.core import QgsVectorLayer, QgsGeometry

JALUR = r"D:/KPH_Contoh/paket-i3/Survei_Lapangan.gpkg"
BAKU = {"Sehat", "Terserang Hama", "Tebangan Liar"}
PERIODE = ("2026-09-01", "2026-09-12")          # tanggal survei yang sah (teks ISO, bisa dibandingkan urutannya)
BATAS_TINGGI = (0, 60)
BATAS_AKURASI = 5.0

titik = QgsVectorLayer(JALUR + "|layername=Titik_Survei", "Titik_Survei", "ogr")
batas = QgsVectorLayer(JALUR + "|layername=Batas_KPH", "Batas_KPH", "ogr")
assert titik.isValid() and batas.isValid(), "Layer tidak terbaca: periksa JALUR"
fitur = list(titik.getFeatures())
petak = {f["NAMA_KPH"]: f.geometry() for f in batas.getFeatures()}

temuan = {}                                        # nama pemeriksaan -> daftar ID_Survei bermasalah


def catat(nama, ids):
    temuan[nama] = sorted(ids)


# 1. Kelengkapan: Kondisi tidak boleh kosong
catat("Kondisi kosong", [f["ID_Survei"] for f in fitur if f["Kondisi"] is None or str(f["Kondisi"]).strip() == ""])
# 2. Nilai baku: Kondisi harus persis salah satu pilihan (huruf besar-kecil dan spasi dihitung)
catat("Kondisi tidak baku", [f["ID_Survei"] for f in fitur if f["Kondisi"] is not None and f["Kondisi"] not in BAKU])
# 3. Rentang: tinggi pohon masuk akal
catat("Tinggi di luar rentang", [f["ID_Survei"] for f in fitur
                                 if f["Tinggi_Phn"] is not None and not (BATAS_TINGGI[0] <= f["Tinggi_Phn"] <= BATAS_TINGGI[1])])
# 4. Tanggal di luar periode survei
catat("Tanggal di luar periode", [f["ID_Survei"] for f in fitur
                                  if f["Tgl_Survei"] is not None and not (PERIODE[0] <= f["Tgl_Survei"].toString("yyyy-MM-dd") <= PERIODE[1])])
# 5. Akurasi GNSS buruk
catat("Akurasi lebih dari %.0f m" % BATAS_AKURASI, [f["ID_Survei"] for f in fitur if f["Akurasi_m"] is not None and f["Akurasi_m"] > BATAS_AKURASI])
# 6. ID ganda
hitung_id = Counter(f["ID_Survei"] for f in fitur)
catat("ID ganda", [i for i, n in hitung_id.items() if n > 1])
# 7. Koordinat kembar (dibulatkan ke 1 mm)
hitung_xy = Counter((round(f.geometry().asPoint().x(), 3), round(f.geometry().asPoint().y(), 3)) for f in fitur)
kembar = {xy for xy, n in hitung_xy.items() if n > 1}
catat("Koordinat kembar", [f["ID_Survei"] for f in fitur
                           if (round(f.geometry().asPoint().x(), 3), round(f.geometry().asPoint().y(), 3)) in kembar])
# 8. Letak: titik harus berada di dalam salah satu petak, dan petaknya harus sama dengan label KPH
di_luar, salah_label = [], []
for f in fitur:
    g = f.geometry()
    dalam = [nama for nama, pg in petak.items() if g.within(pg)]
    if not dalam:
        di_luar.append(f["ID_Survei"])
    elif f["KPH"] not in dalam:
        salah_label.append(f["ID_Survei"])
catat("Di luar semua petak", di_luar)
catat("Label KPH tidak sesuai letak", salah_label)

print("Jumlah baris diperiksa:", len(fitur))
for nama, ids in temuan.items():
    print("%-32s %2d  %s" % (nama, len(ids), ", ".join(ids)))
