<?php
// core/helpers.php

/**
 * Haversine Formula - menghitung jarak antara dua koordinat (meter)
 */
function haversine(float $lat1, float $lng1, float $lat2, float $lng2): float {
    $R = 6371000; // radius bumi meter
    $phi1 = deg2rad($lat1);
    $phi2 = deg2rad($lat2);
    $dphi = deg2rad($lat2 - $lat1);
    $dlam = deg2rad($lng2 - $lng1);

    $a = sin($dphi / 2) ** 2 + cos($phi1) * cos($phi2) * sin($dlam / 2) ** 2;
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $R * $c;
}

/**
 * Algoritma Skor Prioritas Bantuan (0-100)
 * Semakin tinggi skor = semakin prioritas
 */
function hitungSkorPrioritas(array $warga): array {
    $skor = 0;

    // 1. Penghasilan (30 poin)
    $penghasilan = (int)($warga['penghasilan_bulanan'] ?? 0);
    if ($penghasilan === 0)        $skor += 30;
    elseif ($penghasilan <= 300000) $skor += 25;
    elseif ($penghasilan <= 600000) $skor += 18;
    elseif ($penghasilan <= 1000000) $skor += 10;
    else                            $skor += 3;

    // 2. Jumlah tanggungan (20 poin)
    $tanggungan = (int)($warga['jumlah_tanggungan'] ?? 0);
    if ($tanggungan >= 6)     $skor += 20;
    elseif ($tanggungan >= 4) $skor += 15;
    elseif ($tanggungan >= 2) $skor += 10;
    else                      $skor += 4;

    // 3. Kondisi rumah (15 poin)
    $skor += match($warga['kondisi_rumah'] ?? '') {
        'Sangat Tidak Layak' => 15,
        'Tidak Layak'        => 10,
        'Cukup Layak'        => 5,
        'Layak'              => 1,
        default              => 5
    };

    // 4. Pendidikan (10 poin)
    $skor += match($warga['pendidikan_terakhir'] ?? '') {
        'Tidak Sekolah' => 10,
        'SD'            => 8,
        'SMP'           => 6,
        'SMA'           => 3,
        default         => 1
    };

    // 5. Riwayat penyakit (10 poin)
    if (!empty($warga['riwayat_penyakit'])) {
        $penyakit = strtolower($warga['riwayat_penyakit']);
        if (str_contains($penyakit, 'kanker') || str_contains($penyakit, 'gagal ginjal') || str_contains($penyakit, 'stroke')) {
            $skor += 10;
        } elseif (str_contains($penyakit, 'diabetes') || str_contains($penyakit, 'jantung') || str_contains($penyakit, 'tbc')) {
            $skor += 8;
        } else {
            $skor += 5;
        }
    }

    // 6. Lansia (8 poin)
    if (!empty($warga['is_lansia'])) $skor += 8;

    // 7. Disabilitas (7 poin)
    if (!empty($warga['is_disabilitas'])) $skor += 7;

    $skor = min(100, $skor);

    $level = match(true) {
        $skor >= 70 => 'Tinggi',
        $skor >= 40 => 'Sedang',
        default     => 'Rendah'
    };

    return ['skor' => $skor, 'level' => $level];
}

/**
 * Tentukan status kemiskinan berdasarkan penghasilan dan tanggungan
 */
function tentukanStatusKemiskinan(int $penghasilan, int $tanggungan): string {
    $kapita = $tanggungan > 0 ? $penghasilan / $tanggungan : $penghasilan;
    if ($kapita <= 350000) return 'Miskin Ekstrem';
    if ($kapita <= 550000) return 'Miskin';
    return 'Rentan Miskin';
}

/**
 * Generate kode laporan: LPR-YYYYMMDD-XXXX
 */
function generateKodeLaporan(): string {
    $db    = Database::getInstance();
    $today = date('Ymd');
    $count = $db->fetchOne("SELECT COUNT(*)+1 as n FROM laporan_masyarakat WHERE DATE(created_at) = CURDATE()")['n'];
    return 'LPR-' . $today . '-' . str_pad($count, 4, '0', STR_PAD_LEFT);
}

/**
 * Generate kode bantuan: BNT-YYYYMMDD-XXXX
 */
function generateKodeBantuan(): string {
    $db    = Database::getInstance();
    $today = date('Ymd');
    $count = $db->fetchOne("SELECT COUNT(*)+1 as n FROM histori_bantuan WHERE DATE(created_at) = CURDATE()")['n'];
    return 'BNT-' . $today . '-' . str_pad($count, 4, '0', STR_PAD_LEFT);
}

/**
 * Generate password awal/reset yang mudah diketik tetapi tetap acak.
 */
function generatePasswordAkun(): string {
    return 'Sinergi@' . random_int(100000, 999999);
}

/**
 * Kirim kredensial akun via email jika mail server tersedia.
 * Mengembalikan false di instalasi lokal yang belum punya konfigurasi SMTP/sendmail.
 */
function kirimEmailAkun(string $email, string $nama, string $username, string $password, string $aksi = 'dibuat'): bool {
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return false;
    }

    $subject = 'Informasi Akun SINERGI';
    $message = "Yth. {$nama},\n\n"
        . "Akun SINERGI Anda telah {$aksi}.\n\n"
        . "URL Login: " . APP_URL . "/login\n"
        . "Username: {$username}\n"
        . "Password: {$password}\n\n"
        . "Silakan masuk ke sistem dan simpan kredensial ini dengan aman.\n\n"
        . "Salam,\nAdmin SINERGI";

    $headers = [
        'From: SINERGI <noreply@sinergi.local>',
        'Content-Type: text/plain; charset=UTF-8'
    ];

    return @mail($email, $subject, $message, implode("\r\n", $headers));
}

/**
 * Temukan rumah ibadah terdekat berdasarkan Haversine
 */
function findRumahIbadahTerdekat(float $lat, float $lng): ?array {
    $db = Database::getInstance();
    $rumahIbadahs = $db->fetchAll(
        "SELECT ri.*, k.nama as kelurahan FROM rumah_ibadah ri 
         JOIN kelurahan k ON ri.id_kelurahan = k.id
         WHERE ri.is_active = 1"
    );

    $nearest  = null;
    $minDist  = PHP_FLOAT_MAX;

    foreach ($rumahIbadahs as $ri) {
        $dist = haversine($lat, $lng, (float)$ri['lat'], (float)$ri['lng']);
        if ($dist < $minDist) {
            $minDist = $dist;
            $nearest = $ri;
            $nearest['jarak_meter'] = round($dist);
        }
    }
    return $nearest;
}

/**
 * Cek apakah titik berada dalam radius salah satu rumah ibadah
 */
function isInBlindSpot(float $lat, float $lng): bool {
    $db = Database::getInstance();
    $rumahIbadahs = $db->fetchAll("SELECT lat, lng, radius_meter FROM rumah_ibadah WHERE is_active = 1");
    foreach ($rumahIbadahs as $ri) {
        $dist = haversine($lat, $lng, (float)$ri['lat'], (float)$ri['lng']);
        if ($dist <= (float)$ri['radius_meter']) {
            return false;
        }
    }
    return true;
}

/**
 * Format rupiah
 */
function formatRupiah(int $amount): string {
    return 'Rp ' . number_format($amount, 0, ',', '.');
}

/**
 * Format tanggal Indonesia
 */
function formatTanggal(string $date, bool $withTime = false): string {
    if (empty($date) || $date === '0000-00-00') return '-';
    $bulan = ['','Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'];
    $d = new DateTime($date);
    $str = $d->format('j') . ' ' . $bulan[(int)$d->format('n')] . ' ' . $d->format('Y');
    if ($withTime) $str .= ' ' . $d->format('H:i');
    return $str;
}

/**
 * Hitung umur
 */
function hitungUmur(string $tanggalLahir): int {
    if (empty($tanggalLahir)) return 0;
    return (new DateTime($tanggalLahir))->diff(new DateTime())->y;
}

/**
 * Warna marker berdasarkan status kemiskinan
 */
function warnaMiskin(string $status): string {
    return match($status) {
        'Miskin Ekstrem' => '#dc2626',
        'Miskin'         => '#ea580c',
        'Rentan Miskin'  => '#ca8a04',
        default          => '#6b7280'
    };
}

/**
 * Badge HTML status
 */
function statusBadge(string $status): string {
    $map = [
        'menunggu'     => ['bg-yellow-100 text-yellow-800', 'Menunggu'],
        'diproses'     => ['bg-blue-100 text-blue-800', 'Diproses'],
        'terverifikasi'=> ['bg-green-100 text-green-800', 'Terverifikasi'],
        'ditolak'      => ['bg-red-100 text-red-800', 'Ditolak'],
        'aktif'        => ['bg-green-100 text-green-800', 'Aktif'],
        'nonaktif'     => ['bg-gray-100 text-gray-600', 'Nonaktif'],
        'Tinggi'       => ['bg-red-100 text-red-800', 'Tinggi'],
        'Sedang'       => ['bg-yellow-100 text-yellow-800', 'Sedang'],
        'Rendah'       => ['bg-green-100 text-green-800', 'Rendah'],
        'disalurkan'   => ['bg-green-100 text-green-800', 'Disalurkan'],
        'rencana'      => ['bg-blue-100 text-blue-800', 'Rencana'],
        'dibatalkan'   => ['bg-red-100 text-red-800', 'Dibatalkan'],
    ];
    [$cls, $label] = $map[$status] ?? ['bg-gray-100 text-gray-600', $status];
    return "<span class=\"badge $cls\">$label</span>";
}

/**
 * CSRF hidden input
 */
function csrfField(): string {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return '<input type="hidden" name="_token" value="' . htmlspecialchars($_SESSION['csrf_token']) . '">';
}

/**
 * Set flash message ke session.
 * Gunakan fungsi ini (bukan tulis langsung ke $_SESSION['flash']) agar
 * kode_laporan / kode_bantuan disimpan sebagai key terpisah — bukan
 * ditempel ke dalam string pesan — sehingga tidak ikut terhapus saat
 * flashMessage() dipanggil.
 *
 * Contoh penggunaan:
 *   setFlash('success', 'Laporan berhasil disimpan.', ['kode_laporan' => $kode]);
 *   setFlash('error', 'Terjadi kesalahan.');
 */
function setFlash(string $type, string $message, array $extra = []): void {
    $_SESSION['flash'] = array_merge(['type' => $type, 'message' => $message], $extra);
}

/**
 * Flash message display.
 *
 * FIX Bug 1 — unset dilakukan SETELAH semua data flash dibaca, bukan di
 *             tengah-tengah, sehingga kode_laporan/kode_bantuan yang
 *             mungkin dipakai lapor.php masih tersedia selama request ini.
 *
 * FIX Bug 2 — pesan flash boleh mengandung <strong> dan <br> (supaya kode
 *             laporan bisa ditebalkan), tapi semua tag lain tetap di-escape
 *             agar aman dari XSS.
 *
 * Jika flash mengandung 'kode_laporan' atau 'kode_bantuan', nilainya
 * otomatis disisipkan ke baris kedua pesan dalam tag <strong>.
 */
function flashMessage(): string {
    if (empty($_SESSION['flash'])) return '';

    // Baca dulu seluruh data — JANGAN unset sebelum semua field diambil
    $flash = $_SESSION['flash'];
    unset($_SESSION['flash']);   // hapus sekarang, setelah semua field tersalin ke $flash

    $type    = $flash['type']    ?? 'info';
    $message = $flash['message'] ?? '';

    // Sisipkan kode laporan / bantuan sebagai baris ke-2 jika ada
    if (!empty($flash['kode_laporan'])) {
        $kode     = htmlspecialchars($flash['kode_laporan'], ENT_QUOTES, 'UTF-8');
        $message .= '<br>Kode Laporan: <strong>' . $kode . '</strong>';
    } elseif (!empty($flash['kode_bantuan'])) {
        $kode     = htmlspecialchars($flash['kode_bantuan'], ENT_QUOTES, 'UTF-8');
        $message .= '<br>Kode Bantuan: <strong>' . $kode . '</strong>';
    }

    // Escape pesan utama — lalu kembalikan <strong> dan <br> yang sudah kita sisipkan
    // Alur: escape semua → unescape hanya tag yang kita izinkan
    $safe = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
    $safe = str_replace(
        ['&lt;strong&gt;', '&lt;/strong&gt;', '&lt;br&gt;'],
        ['<strong>',       '</strong>',        '<br>'],
        $safe
    );

    $icon = match($type) {
        'success' => '✓',
        'error'   => '✕',
        'warning' => '⚠',
        default   => 'ℹ',
    };
    $cls = match($type) {
        'success' => 'flash-success',
        'error'   => 'flash-error',
        'warning' => 'flash-warning',
        default   => 'flash-info',
    };

    return "<div class=\"flash-message $cls\"><span>$icon</span><span>$safe</span></div>";
}

/**
 * Escape HTML
 */
function e(string $str): string {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

/**
 * Asset URL
 */
function asset(string $path): string {
    return APP_URL . '/public/' . ltrim($path, '/');
}

/**
 * Upload URL
 */
function uploadUrl(string $filename): string {
    if (empty($filename)) return asset('images/placeholder.png');
    return APP_URL . '/public/images/uploads/' . $filename;
}
