<?php
/**
 * Menghitung jarak antara dua koordinat menggunakan formula Haversine.
 * @param float $lat1 Latitude titik pertama
 * @param float $lon1 Longitude titik pertama
 * @param float $lat2 Latitude titik kedua
 * @param float $lon2 Longitude titik kedua
 * @return float Jarak dalam satuan meter
 */
function calculateHaversineDistance($lat1, $lon1, $lat2, $lon2) {
    $earthRadius = 6371000; // Radius bumi dalam meter

    $latFrom = deg2rad($lat1);
    $lonFrom = deg2rad($lon1);
    $latTo = deg2rad($lat2);
    $lonTo = deg2rad($lon2);

    $latDelta = $latTo - $latFrom;
    $lonDelta = $lonTo - $lonFrom;

    $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
        cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
        
    return $angle * $earthRadius;
}

function calculateOsrmRouteDistance($lat1, $lon1, $lat2, $lon2): ?float
{
    $coordinates = sprintf(
        '%.8F,%.8F;%.8F,%.8F',
        $lon1,
        $lat1,
        $lon2,
        $lat2
    );
    $url = 'https://router.project-osrm.org/route/v1/driving/' . $coordinates . '?overview=false&alternatives=false&steps=false';

    $ch = curl_init($url);
    if ($ch === false) {
        return null;
    }

    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 4,
        CURLOPT_TIMEOUT => 8,
        CURLOPT_USERAGENT => 'WebGIS-Peduli/1.0',
    ]);

    $response = curl_exec($ch);
    $httpCode = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($response === false || $httpCode !== 200) {
        return null;
    }

    $json = json_decode($response, true);
    if (!is_array($json) || ($json['code'] ?? '') !== 'Ok') {
        return null;
    }

    $distance = $json['routes'][0]['distance'] ?? null;

    return is_numeric($distance) ? (float)$distance : null;
}

function calculateRoadDistance($lat1, $lon1, $lat2, $lon2): ?float
{
    return calculateOsrmRouteDistance((float)$lat1, (float)$lon1, (float)$lat2, (float)$lon2);
}

function ensurePendudukDistanceColumns(PDO $pdo): void
{
    $stmt = $pdo->query("SHOW COLUMNS FROM penduduk_miskin LIKE 'jarak_rute_m'");
    if ($stmt->fetch() === false) {
        $pdo->exec("ALTER TABLE penduduk_miskin ADD COLUMN jarak_rute_m DECIMAL(10, 2) NULL AFTER jarak_m");
    }
}

function calculatePendudukCoverage(PDO $pdo, float $lat, float $lng): array
{
    $stmtRi = $pdo->query("SELECT id, lat, lng, radius FROM rumah_ibadah");
    $rumahIbadah = $stmtRi->fetchAll(PDO::FETCH_ASSOC);

    $nearest = null;
    $nearestCovered = null;

    foreach ($rumahIbadah as $ri) {
        $distance = calculateHaversineDistance($lat, $lng, (float)$ri['lat'], (float)$ri['lng']);
        $result = [
            'ibadah_id' => (int)$ri['id'],
            'ri_lat' => (float)$ri['lat'],
            'ri_lng' => (float)$ri['lng'],
            'jarak_m' => round($distance, 2),
            'distance' => $distance,
        ];

        if ($nearest === null || $distance < $nearest['distance']) {
            $nearest = $result;
        }

        if ($distance <= (float)$ri['radius'] && ($nearestCovered === null || $distance < $nearestCovered['distance'])) {
            $nearestCovered = $result;
        }
    }

    $selected = $nearestCovered ?? $nearest;
    $routeDistance = null;

    if ($selected !== null) {
        $routeDistance = calculateRoadDistance($lat, $lng, $selected['ri_lat'], $selected['ri_lng']);
    }

    return [
        'ibadah_id' => $selected['ibadah_id'] ?? null,
        'jarak_m' => $selected['jarak_m'] ?? null,
        'jarak_rute_m' => $routeDistance !== null ? round($routeDistance, 2) : null,
        'is_blank_spot' => $nearestCovered === null ? 1 : 0,
    ];
}

function recalculateAllPendudukCoverage(PDO $pdo): void
{
    ensurePendudukDistanceColumns($pdo);

    $stmt = $pdo->query("SELECT id, lat, lng FROM penduduk_miskin");
    $penduduk = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $update = $pdo->prepare("
        UPDATE penduduk_miskin
        SET ibadah_id = ?, jarak_m = ?, jarak_rute_m = ?, is_blank_spot = ?
        WHERE id = ?
    ");

    foreach ($penduduk as $row) {
        $coverage = calculatePendudukCoverage($pdo, (float)$row['lat'], (float)$row['lng']);
        $update->execute([
            $coverage['ibadah_id'],
            $coverage['jarak_m'],
            $coverage['jarak_rute_m'],
            $coverage['is_blank_spot'],
            $row['id'],
        ]);
    }
}
