<?php
// api/redistribusi.php
// Fitur 1: Redistribusi Bantuan antar Rumah Ibadah
// Method: GET (analisis), POST (buat saran manual), PUT (update status), DELETE

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

require_once '../config/db.php';
require_once 'middleware.php';

/* ─────────────────────────────────────────────
   HELPER: ambil konfigurasi dari DB
───────────────────────────────────────────── */
function getKonfig(PDO $pdo, string $kunci, $default = null) {
    $stmt = $pdo->prepare("SELECT nilai, tipe FROM konfigurasi_sistem WHERE kunci = ?");
    $stmt->execute([$kunci]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$row) return $default;
    return match($row['tipe']) {
        'integer' => (int)$row['nilai'],
        'decimal' => (float)$row['nilai'],
        'boolean' => filter_var($row['nilai'], FILTER_VALIDATE_BOOLEAN),
        default   => $row['nilai'],
    };
}

/* ─────────────────────────────────────────────
   CORE: Hitung beban tiap rumah ibadah
   berdasarkan radius dan jumlah warga miskin
───────────────────────────────────────────── */
function hitungBebanIbadah(PDO $pdo, float $radius): array {
    // Ambil semua rumah ibadah
    $ibadahList = $pdo->query("SELECT * FROM rumah_ibadah ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);

    // Ambil semua rumah warga dengan status relevan
    $wargaList = $pdo->query("
        SELECT id, latitude, longitude, kategori_kemiskinan,
               status_bantuan, rekomendasi_bantuan, jumlah_tanggungan,
               penghasilan_bulanan, status_kemandirian, skor_kemandirian,
               dikelola_oleh_ibadah_id
        FROM rumah_warga
        WHERE status_kemandirian NOT IN ('mandiri')
          AND kategori_kemiskinan IN ('sangat_miskin','miskin','rentan_miskin')
    ")->fetchAll(PDO::FETCH_ASSOC);

    $result = [];

    foreach ($ibadahList as $ibadah) {
        $lat1 = (float)$ibadah['latitude'];
        $lng1 = (float)$ibadah['longitude'];
        $rad  = $ibadah['radius_primer'] ?? $radius;
        $kap  = (int)($ibadah['kapasitas_kk'] ?? 20);

        $wargaDalam = [];
        foreach ($wargaList as $warga) {
            $kelolaId = $warga['dikelola_oleh_ibadah_id'];
            if ($kelolaId !== null) {
                if ((int)$kelolaId === (int)$ibadah['id']) {
                    // Explicitly assigned to this ibadah
                    $d = haversine($lat1, $lng1, (float)$warga['latitude'], (float)$warga['longitude']);
                    $wargaDalam[] = array_merge($warga, ['jarak_meter' => round($d)]);
                }
            } else {
                // Not assigned explicitly, check radius
                $d = haversine($lat1, $lng1, (float)$warga['latitude'], (float)$warga['longitude']);
                if ($d <= $rad) {
                    $wargaDalam[] = array_merge($warga, ['jarak_meter' => round($d)]);
                }
            }
        }

        // Hitung kategori
        $sangat  = count(array_filter($wargaDalam, fn($w) => $w['kategori_kemiskinan'] === 'sangat_miskin'));
        $miskin  = count(array_filter($wargaDalam, fn($w) => $w['kategori_kemiskinan'] === 'miskin'));
        $rentan  = count(array_filter($wargaDalam, fn($w) => $w['kategori_kemiskinan'] === 'rentan_miskin'));
        $total   = count($wargaDalam);

        // Indeks beban: (sangat_miskin*3 + miskin*2 + rentan*1) / kapasitas
        // Skor 0-100, > 100 = overload
        $bobotBeban = ($sangat * 3 + $miskin * 2 + $rentan * 1);
        $maxBobot   = $kap * 3; // kalau semua sangat miskin
        $pctBeban   = $maxBobot > 0 ? round(min($bobotBeban / $maxBobot * 100, 200)) : 0;

        // Rasio kemiskinan: berapa % warga dalam radius yang masuk kategori miskin
        $rasioMiskin = $total > 0 ? round(($sangat + $miskin) / $total * 100) : 0;

        // Status beban
        $statusBeban = match(true) {
            $total === 0            => 'kosong',
            $total < $kap * 0.5    => 'ringan',
            $total <= $kap         => 'normal',
            $total <= $kap * 1.3   => 'padat',
            default                => 'overload',
        };

        $result[$ibadah['id']] = [
            'ibadah'         => $ibadah,
            'radius_dipakai' => $rad,
            'kapasitas'      => $kap,
            'total_warga'    => $total,
            'sangat_miskin'  => $sangat,
            'miskin'         => $miskin,
            'rentan_miskin'  => $rentan,
            'rasio_miskin'   => $rasioMiskin,
            'bobot_beban'    => $bobotBeban,
            'pct_beban'      => $pctBeban,
            'status_beban'   => $statusBeban,
            'surplus_kapasitas' => max(0, $kap - $total),
            'defisit_kapasitas' => max(0, $total - $kap),
            'warga_list'     => $wargaDalam,
        ];
    }

    return $result;
}

/* ─────────────────────────────────────────────
   CORE: Generate saran redistribusi otomatis
───────────────────────────────────────────── */
function generateSaranRedistribusi(array $bebanData): array {
    $saranList = [];

    // Pisahkan ibadah surplus vs defisit
    $surplus = array_filter($bebanData, fn($d) => $d['status_beban'] === 'ringan' || $d['status_beban'] === 'kosong');
    $defisit = array_filter($bebanData, fn($d) => in_array($d['status_beban'], ['padat','overload']));

    // Sort: defisit paling parah dulu, surplus paling longgar dulu
    uasort($surplus, fn($a,$b) => $a['pct_beban'] <=> $b['pct_beban']);
    uasort($defisit, fn($a,$b) => $b['pct_beban'] <=> $a['pct_beban']);

    foreach ($defisit as $def) {
        foreach ($surplus as &$sur) {
            if ($sur['surplus_kapasitas'] <= 0) continue;

            $ibadahDef = $def['ibadah'];
            $ibadahSur = $sur['ibadah'];

            // Hitung jarak antar kedua ibadah
            $jarakKm = round(haversine(
                (float)$ibadahDef['latitude'], (float)$ibadahDef['longitude'],
                (float)$ibadahSur['latitude'], (float)$ibadahSur['longitude']
            ) / 1000, 2);

            // Hanya sarankan jika jarak tidak terlalu jauh (< 5km)
            if ($jarakKm > 5) continue;

            $jumlahPindah = min($def['defisit_kapasitas'], $sur['surplus_kapasitas']);
            if ($jumlahPindah <= 0) continue;

            // Estimasi dana: rata-rata penghasilan warga * faktor bantuan
            $estDana = $jumlahPindah * 200000; // estimasi Rp200rb/KK/bulan

            // Tingkat prioritas
            $prioritas = match(true) {
                $def['rasio_miskin'] >= 80 => 'tinggi',
                $def['rasio_miskin'] >= 50 => 'sedang',
                default                    => 'rendah',
            };

            $saranList[] = [
                'pengirim_id'    => (int)$ibadahSur['id'],
                'pengirim_nama'  => $ibadahSur['nama'],
                'penerima_id'    => (int)$ibadahDef['id'],
                'penerima_nama'  => $ibadahDef['nama'],
                'jumlah_kk'      => $jumlahPindah,
                'estimasi_dana'  => $estDana,
                'jarak_km'       => $jarakKm,
                'prioritas'      => $prioritas,
                'alasan'         => sprintf(
                    '%s memiliki surplus %d kapasitas (beban %d%%), sementara %s kelebihan %d KK (beban %d%%) dengan rasio kemiskinan %d%%.',
                    $ibadahSur['nama'],
                    $sur['surplus_kapasitas'],
                    $sur['pct_beban'],
                    $ibadahDef['nama'],
                    $def['defisit_kapasitas'],
                    $def['pct_beban'],
                    $def['rasio_miskin']
                ),
            ];

            // Kurangi surplus yang sudah dipakai
            $sur['surplus_kapasitas'] -= $jumlahPindah;
            break;
        }
    }

    // Sort hasil saran berdasarkan prioritas
    usort($saranList, function($a, $b) {
        $p = ['tinggi' => 0, 'sedang' => 1, 'rendah' => 2];
        return ($p[$a['prioritas']] ?? 9) <=> ($p[$b['prioritas']] ?? 9);
    });

    return $saranList;
}

function haversine(float $lat1, float $lng1, float $lat2, float $lng2): float {
    $R    = 6371000;
    $dLat = deg2rad($lat2 - $lat1);
    $dLng = deg2rad($lng2 - $lng1);
    $a    = sin($dLat/2)**2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng/2)**2;
    return $R * 2 * atan2(sqrt($a), sqrt(1-$a));
}

/* ─────────────────────────────────────────────
   ROUTING
───────────────────────────────────────────── */
try {
    // Hanya Admin yang bisa mengakses fitur redistribusi bantuan / analisis spasial
    requireAuth(['admin']);

    // Guard: PDO connection must be available
    if (!$pdo) {
        throw new RuntimeException('Koneksi database (PDO) tidak tersedia. Pastikan XAMPP MySQL aktif.');
    }
    
    $method = $_SERVER['REQUEST_METHOD'];

    if ($method === 'GET') {
        $action = $_GET['action'] ?? 'analisis';

        if ($action === 'analisis') {
            // Analisis beban semua rumah ibadah
            $radius = (float)($_GET['radius'] ?? getKonfig($pdo, 'kapasitas_default_ibadah') ?? 500);
            $beban  = hitungBebanIbadah($pdo, $radius);

            // Hapus warga_list dari response utama (terlalu besar)
            $ringkasan = array_map(function($d) {
                $r = $d;
                unset($r['warga_list']);
                return $r;
            }, $beban);

            echo json_encode([
                'success'  => true,
                'data'     => array_values($ringkasan),
                'saran'    => generateSaranRedistribusi($beban),
                'summary'  => [
                    'total_ibadah'  => count($beban),
                    'overload'      => count(array_filter($beban, fn($d) => $d['status_beban'] === 'overload')),
                    'padat'         => count(array_filter($beban, fn($d) => $d['status_beban'] === 'padat')),
                    'normal'        => count(array_filter($beban, fn($d) => $d['status_beban'] === 'normal')),
                    'ringan'        => count(array_filter($beban, fn($d) => $d['status_beban'] === 'ringan')),
                    'kosong'        => count(array_filter($beban, fn($d) => $d['status_beban'] === 'kosong')),
                ],
            ]);

        } elseif ($action === 'riwayat') {
            // Riwayat keputusan redistribusi
            $limit  = (int)($_GET['limit'] ?? 20);
            $status = $_GET['status'] ?? null;
            $sql    = "SELECT r.*, 
                              ip.nama as pengirim_nama, ip.jenis as pengirim_jenis,
                              ir.nama as penerima_nama, ir.jenis as penerima_jenis
                       FROM redistribusi_bantuan r
                       JOIN rumah_ibadah ip ON r.ibadah_pengirim_id = ip.id
                       JOIN rumah_ibadah ir ON r.ibadah_penerima_id = ir.id";
            if ($status) $sql .= " WHERE r.status = " . $pdo->quote($status);
            $sql .= " ORDER BY r.tanggal_saran DESC LIMIT $limit";
            $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode(['success' => true, 'data' => $rows]);

        } elseif ($action === 'detail') {
            // Detail beban 1 ibadah
            $id     = (int)($_GET['id'] ?? 0);
            $radius = (float)($_GET['radius'] ?? 500);
            $beban  = hitungBebanIbadah($pdo, $radius);
            if (!isset($beban[$id])) {
                echo json_encode(['success' => false, 'message' => 'Rumah ibadah tidak ditemukan']);
                exit;
            }
            echo json_encode(['success' => true, 'data' => $beban[$id]]);
        }

    } elseif ($method === 'POST') {
        // Simpan saran redistribusi (dari sistem atau manual admin)
        $body = json_decode(file_get_contents('php://input'), true);

        $stmt = $pdo->prepare("
            INSERT INTO redistribusi_bantuan
              (ibadah_pengirim_id, ibadah_penerima_id, jumlah_kk, estimasi_dana,
               status, catatan_sistem, catatan_admin, periode_bulan)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ");
        $stmt->execute([
            (int)$body['pengirim_id'],
            (int)$body['penerima_id'],
            (int)($body['jumlah_kk'] ?? 0),
            (float)($body['estimasi_dana'] ?? 0),
            $body['status'] ?? 'saran_sistem',
            $body['catatan_sistem'] ?? null,
            $body['catatan_admin'] ?? null,
            $body['periode_bulan'] ?? date('Y-m'),
        ]);

        $redistId = (int)$pdo->lastInsertId();

        // Jika disetujui, alihkan warga dari penerima (defisit) ke pengirim (surplus)
        if (($body['status'] ?? '') === 'disetujui') {
            $penerimaId = (int)$body['penerima_id'];
            $pengirimId = (int)$body['pengirim_id'];
            $limit      = (int)($body['jumlah_kk'] ?? 0);
            
            if (isset($body['warga_ids']) && is_array($body['warga_ids']) && count($body['warga_ids']) > 0) {
                $ids = array_map('intval', $body['warga_ids']);
                $placeholders = str_repeat('?,', count($ids) - 1) . '?';
                $updateStmt = $pdo->prepare("UPDATE rumah_warga SET dikelola_oleh_ibadah_id = ? WHERE id IN ($placeholders)");
                $params = array_merge([$pengirimId], $ids);
                $updateStmt->execute($params);
            } elseif ($limit > 0) {
                // Ambil radius penerima (untuk mencari warga yang saat ini masuk radiusnya)
                $stmtPen = $pdo->prepare("SELECT latitude, longitude, radius_primer FROM rumah_ibadah WHERE id = ?");
                $stmtPen->execute([$penerimaId]);
                $penerima = $stmtPen->fetch(PDO::FETCH_ASSOC);
                
                // Ambil koordinat pengirim (untuk mencari warga terdekat ke pengirim)
                $stmtPeng = $pdo->prepare("SELECT latitude, longitude FROM rumah_ibadah WHERE id = ?");
                $stmtPeng->execute([$pengirimId]);
                $pengirim = $stmtPeng->fetch(PDO::FETCH_ASSOC);
                
                if ($penerima && $pengirim) {
                    $radPenerima = (float)($penerima['radius_primer'] ?? 500);
                    
                    // Ambil warga yang dikelola oleh penerima atau belum dikelola siapapun
                    $stmtWarga = $pdo->prepare("SELECT id, latitude, longitude, dikelola_oleh_ibadah_id FROM rumah_warga WHERE (dikelola_oleh_ibadah_id = ? OR dikelola_oleh_ibadah_id IS NULL) AND kategori_kemiskinan IN ('sangat_miskin', 'miskin', 'rentan_miskin') AND status_kemandirian != 'mandiri'");
                    $stmtWarga->execute([$penerimaId]);
                    $wargaList = $stmtWarga->fetchAll(PDO::FETCH_ASSOC);
                    
                    $eligible = [];
                    foreach ($wargaList as $w) {
                        // Jika sudah secara eksplisit dikelola oleh penerima, atau jika NULL dan masih dalam radius penerima
                        $isManaged = ($w['dikelola_oleh_ibadah_id'] == $penerimaId);
                        $distPenerima = haversine((float)$w['latitude'], (float)$w['longitude'], (float)$penerima['latitude'], (float)$penerima['longitude']);
                        
                        if ($isManaged || $distPenerima <= $radPenerima) {
                            $distPengirim = haversine((float)$w['latitude'], (float)$w['longitude'], (float)$pengirim['latitude'], (float)$pengirim['longitude']);
                            $w['dist_pengirim'] = $distPengirim;
                            $eligible[] = $w;
                        }
                    }
                    
                    // Urutkan warga berdasarkan jarak terdekat ke rumah ibadah pengirim (surplus)
                    usort($eligible, fn($a, $b) => $a['dist_pengirim'] <=> $b['dist_pengirim']);
                    
                    // Ambil sejumlah $limit
                    $toTransfer = array_slice($eligible, 0, $limit);
                    
                    if (!empty($toTransfer)) {
                        $ids = array_column($toTransfer, 'id');
                        $placeholders = str_repeat('?,', count($ids) - 1) . '?';
                        $updateStmt = $pdo->prepare("UPDATE rumah_warga SET dikelola_oleh_ibadah_id = ? WHERE id IN ($placeholders)");
                        $params = array_merge([$pengirimId], $ids);
                        $updateStmt->execute($params);
                    }
                }
            }
        }

        echo json_encode([
            'success' => true,
            'message' => 'Saran redistribusi berhasil disimpan',
            'id'      => $redistId,
        ]);

    } elseif ($method === 'PUT') {
        // Update status keputusan admin
        $body = json_decode(file_get_contents('php://input'), true);
        $id   = (int)($body['id'] ?? 0);

        $stmt = $pdo->prepare("
            UPDATE redistribusi_bantuan
            SET status            = ?,
                catatan_admin     = ?,
                disetujui_oleh    = ?,
                tanggal_keputusan = NOW()
            WHERE id = ?
        ");
        $stmt->execute([
            $body['status'],
            $body['catatan_admin'] ?? null,
            $body['disetujui_oleh'] ?? null,
            $id,
        ]);

        echo json_encode(['success' => true, 'message' => 'Status redistribusi diperbarui']);

    } elseif ($method === 'DELETE') {
        $id   = (int)($_GET['id'] ?? 0);
        $stmt = $pdo->prepare("DELETE FROM redistribusi_bantuan WHERE id = ?");
        $stmt->execute([$id]);
        echo json_encode(['success' => true, 'message' => 'Data redistribusi dihapus']);
    }

} catch (Throwable $e) {
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}