<?php
/**
 * Polygon Intersection and Overlap Detection Functions
 * For detecting when land parcels overlap or one is inside another
 */

/**
 * Check if a point is inside a polygon using ray casting algorithm
 * @param array $point ['lat' => float, 'lng' => float]
 * @param array $polygon Array of points [['lat' => float, 'lng' => float], ...]
 * @return bool
 */
function isPointInPolygon($point, $polygon) {
    $n = count($polygon);
    if ($n < 3) return false;

    $inside = false;
    $x = $point['lng'];
    $y = $point['lat'];

    $j = $n - 1;
    for ($i = 0; $i < $n; $j = $i++) {
        $xi = $polygon[$i]['lng'];
        $yi = $polygon[$i]['lat'];
        $xj = $polygon[$j]['lng'];
        $yj = $polygon[$j]['lat'];

        if ((($yi > $y) != ($yj > $y)) && ($x < ($xj - $xi) * ($y - $yi) / ($yj - $yi) + $xi)) {
            $inside = !$inside;
        }
    }

    return $inside;
}

/**
 * Check if two line segments intersect
 * @return bool
 */
function doLinesIntersect($p1, $p2, $p3, $p4) {
    $d1 = direction($p3, $p4, $p1);
    $d2 = direction($p3, $p4, $p2);
    $d3 = direction($p1, $p2, $p3);
    $d4 = direction($p1, $p2, $p4);

    if ((($d1 > 0 && $d2 < 0) || ($d1 < 0 && $d2 > 0)) &&
        (($d3 > 0 && $d4 < 0) || ($d3 < 0 && $d4 > 0))) {
        return true;
    }

    if ($d1 == 0 && onSegment($p3, $p4, $p1)) return true;
    if ($d2 == 0 && onSegment($p3, $p4, $p2)) return true;
    if ($d3 == 0 && onSegment($p1, $p2, $p3)) return true;
    if ($d4 == 0 && onSegment($p1, $p2, $p4)) return true;

    return false;
}

function direction($p1, $p2, $p3) {
    return ($p3['lng'] - $p1['lng']) * ($p2['lat'] - $p1['lat']) -
           ($p2['lng'] - $p1['lng']) * ($p3['lat'] - $p1['lat']);
}

function onSegment($p1, $p2, $p) {
    return min($p1['lng'], $p2['lng']) <= $p['lng'] && $p['lng'] <= max($p1['lng'], $p2['lng']) &&
           min($p1['lat'], $p2['lat']) <= $p['lat'] && $p['lat'] <= max($p1['lat'], $p2['lat']);
}

/**
 * Check if two polygons intersect (edges cross each other)
 * @param array $polygon1 Array of points
 * @param array $polygon2 Array of points
 * @return bool
 */
function doPolygonsIntersect($polygon1, $polygon2) {
    $n1 = count($polygon1);
    $n2 = count($polygon2);

    // Check if any edge of polygon1 intersects with any edge of polygon2
    for ($i = 0; $i < $n1; $i++) {
        $p1 = $polygon1[$i];
        $p2 = $polygon1[($i + 1) % $n1];

        for ($j = 0; $j < $n2; $j++) {
            $p3 = $polygon2[$j];
            $p4 = $polygon2[($j + 1) % $n2];

            if (doLinesIntersect($p1, $p2, $p3, $p4)) {
                return true;
            }
        }
    }

    return false;
}

/**
 * Check if polygon1 is completely inside polygon2
 * @param array $polygon1 The polygon to check if inside
 * @param array $polygon2 The containing polygon
 * @return bool
 */
function isPolygonInsidePolygon($polygon1, $polygon2) {
    // All points of polygon1 must be inside polygon2
    foreach ($polygon1 as $point) {
        if (!isPointInPolygon($point, $polygon2)) {
            return false;
        }
    }

    // And no edges should intersect
    if (doPolygonsIntersect($polygon1, $polygon2)) {
        return false;
    }

    return true;
}

/**
 * Calculate the area of a polygon using Shoelace formula (returns sq meters)
 * @param array $polygon Array of points
 * @return float Area in square meters
 */
function calculatePolygonAreaMeters($polygon) {
    $n = count($polygon);
    if ($n < 3) return 0;

    $area = 0;
    $j = $n - 1;

    for ($i = 0; $i < $n; $i++) {
        $x1 = $polygon[$j]['lng'] * 111320 * cos(deg2rad($polygon[$j]['lat']));
        $y1 = $polygon[$j]['lat'] * 110540;
        $x2 = $polygon[$i]['lng'] * 111320 * cos(deg2rad($polygon[$i]['lat']));
        $y2 = $polygon[$i]['lat'] * 110540;

        $area += ($x1 + $x2) * ($y1 - $y2);
        $j = $i;
    }

    return abs($area / 2);
}

/**
 * Calculate approximate overlap area between two polygons
 * Uses a simple grid-based approach for estimation
 * @param array $polygon1
 * @param array $polygon2
 * @return float Estimated overlap area in square meters
 */
function calculateOverlapArea($polygon1, $polygon2) {
    // Find bounding box that contains both polygons
    $minLat = PHP_FLOAT_MAX;
    $maxLat = -PHP_FLOAT_MAX;
    $minLng = PHP_FLOAT_MAX;
    $maxLng = -PHP_FLOAT_MAX;

    foreach (array_merge($polygon1, $polygon2) as $point) {
        $minLat = min($minLat, $point['lat']);
        $maxLat = max($maxLat, $point['lat']);
        $minLng = min($minLng, $point['lng']);
        $maxLng = max($maxLng, $point['lng']);
    }

    // Create a grid and count points in both polygons
    $gridSize = 50; // 50x50 grid
    $latStep = ($maxLat - $minLat) / $gridSize;
    $lngStep = ($maxLng - $minLng) / $gridSize;

    $overlapCount = 0;
    $totalChecked = 0;

    for ($i = 0; $i < $gridSize; $i++) {
        for ($j = 0; $j < $gridSize; $j++) {
            $testPoint = [
                'lat' => $minLat + ($i + 0.5) * $latStep,
                'lng' => $minLng + ($j + 0.5) * $lngStep
            ];

            $inPolygon1 = isPointInPolygon($testPoint, $polygon1);
            $inPolygon2 = isPointInPolygon($testPoint, $polygon2);

            if ($inPolygon1 || $inPolygon2) {
                $totalChecked++;
            }

            if ($inPolygon1 && $inPolygon2) {
                $overlapCount++;
            }
        }
    }

    if ($totalChecked == 0) return 0;

    // Calculate bounding box area
    $width = ($maxLng - $minLng) * 111320 * cos(deg2rad(($minLat + $maxLat) / 2));
    $height = ($maxLat - $minLat) * 110540;
    $boundingArea = $width * $height;

    // Estimate overlap area based on grid sampling
    $overlapRatio = $overlapCount / ($gridSize * $gridSize);
    return $boundingArea * $overlapRatio;
}

/**
 * Comprehensive overlap detection between a new land and existing lands
 * @param mysqli $conn Database connection
 * @param int $newLandId ID of the new land
 * @param array $newPoints Array of points for the new land
 * @return array Array of detected overlaps with details
 */
function detectLandOverlaps($conn, $newLandId, $newPoints) {
    $overlaps = [];

    // Get all other lands with their beacon points
    $sql = "SELECT l.id, l.land_name, l.user_id, u.full_name as owner_name, u.username
            FROM lands l
            JOIN users u ON l.user_id = u.id
            WHERE l.id != $newLandId";

    $landsResult = mysqli_query($conn, $sql);

    while ($land = mysqli_fetch_assoc($landsResult)) {
        // Get beacon points for this land
        $pointsSql = "SELECT latitude, longitude FROM beacon_points
                      WHERE land_id = {$land['id']} ORDER BY point_order";
        $pointsResult = mysqli_query($conn, $pointsSql);

        $existingPoints = [];
        while ($p = mysqli_fetch_assoc($pointsResult)) {
            $existingPoints[] = [
                'lat' => floatval($p['latitude']),
                'lng' => floatval($p['longitude'])
            ];
        }

        if (count($existingPoints) < 3) continue;

        // Normalize new points format
        $newPolygon = [];
        foreach ($newPoints as $p) {
            $newPolygon[] = [
                'lat' => floatval($p['lat']),
                'lng' => floatval($p['lng'])
            ];
        }

        // Check for various types of overlaps
        $overlapType = null;
        $overlapDetails = [];

        // 1. Check if new land is completely inside existing land
        if (isPolygonInsidePolygon($newPolygon, $existingPoints)) {
            $overlapType = 'NEW_INSIDE_EXISTING';
            $overlapDetails['description'] = "Your new land is completely inside '{$land['land_name']}'";
            $overlapDetails['severity'] = 'critical';
        }
        // 2. Check if existing land is completely inside new land
        elseif (isPolygonInsidePolygon($existingPoints, $newPolygon)) {
            $overlapType = 'EXISTING_INSIDE_NEW';
            $overlapDetails['description'] = "Existing land '{$land['land_name']}' is completely inside your new land";
            $overlapDetails['severity'] = 'critical';
        }
        // 3. Check if polygons intersect (partial overlap)
        elseif (doPolygonsIntersect($newPolygon, $existingPoints)) {
            $overlapType = 'PARTIAL_OVERLAP';
            $overlapArea = calculateOverlapArea($newPolygon, $existingPoints);
            $newArea = calculatePolygonAreaMeters($newPolygon);
            $overlapPercentage = $newArea > 0 ? ($overlapArea / $newArea) * 100 : 0;

            $overlapDetails['description'] = "Your new land partially overlaps with '{$land['land_name']}'";
            $overlapDetails['overlap_area_sqm'] = round($overlapArea, 2);
            $overlapDetails['overlap_percentage'] = round($overlapPercentage, 1);
            $overlapDetails['severity'] = $overlapPercentage > 50 ? 'critical' : ($overlapPercentage > 10 ? 'warning' : 'info');
        }
        else {
            // 4. Check if any beacon points of new land are inside existing land
            $pointsInside = 0;
            foreach ($newPolygon as $point) {
                if (isPointInPolygon($point, $existingPoints)) {
                    $pointsInside++;
                }
            }

            if ($pointsInside > 0) {
                $overlapType = 'POINTS_INSIDE';
                $overlapDetails['description'] = "$pointsInside beacon point(s) of your new land are inside '{$land['land_name']}'";
                $overlapDetails['points_inside'] = $pointsInside;
                $overlapDetails['severity'] = 'warning';
            }

            // 5. Check if any beacon points of existing land are inside new land
            $existingPointsInside = 0;
            foreach ($existingPoints as $point) {
                if (isPointInPolygon($point, $newPolygon)) {
                    $existingPointsInside++;
                }
            }

            if ($existingPointsInside > 0 && $overlapType === null) {
                $overlapType = 'EXISTING_POINTS_INSIDE';
                $overlapDetails['description'] = "$existingPointsInside beacon point(s) of '{$land['land_name']}' are inside your new land";
                $overlapDetails['points_inside'] = $existingPointsInside;
                $overlapDetails['severity'] = 'warning';
            }
        }

        // Record the overlap if detected
        if ($overlapType !== null) {
            $overlaps[] = [
                'land_id' => $land['id'],
                'land_name' => $land['land_name'],
                'owner_id' => $land['user_id'],
                'owner_name' => $land['owner_name'] ?: $land['username'],
                'overlap_type' => $overlapType,
                'details' => $overlapDetails
            ];
        }
    }

    return $overlaps;
}

/**
 * Save overlap alerts to database
 * @param mysqli $conn
 * @param int $newLandId
 * @param array $overlaps Array from detectLandOverlaps
 */
function saveOverlapAlerts($conn, $newLandId, $overlaps) {
    foreach ($overlaps as $overlap) {
        $landId2 = $overlap['land_id'];
        $overlapType = mysqli_real_escape_string($conn, $overlap['overlap_type']);
        $description = mysqli_real_escape_string($conn, $overlap['details']['description']);
        $severity = mysqli_real_escape_string($conn, $overlap['details']['severity']);

        $overlapPercentage = isset($overlap['details']['overlap_percentage'])
            ? floatval($overlap['details']['overlap_percentage'])
            : 100;

        $alertMessage = $description;
        if (isset($overlap['details']['overlap_area_sqm'])) {
            $alertMessage .= " (Approx. {$overlap['details']['overlap_area_sqm']} sqm overlap)";
        }

        $sql = "INSERT INTO overlap_alerts (land_id_1, land_id_2, overlap_percentage, alert_message, status)
                VALUES ($newLandId, $landId2, $overlapPercentage, '$alertMessage', 'pending')";

        mysqli_query($conn, $sql);
    }
}

/**
 * Get all overlap alerts for a specific land
 * @param mysqli $conn
 * @param int $landId
 * @return array
 */
function getOverlapAlertsForLand($conn, $landId) {
    $sql = "SELECT oa.*,
                   l1.land_name as land1_name, u1.full_name as land1_owner,
                   l2.land_name as land2_name, u2.full_name as land2_owner
            FROM overlap_alerts oa
            JOIN lands l1 ON oa.land_id_1 = l1.id
            JOIN lands l2 ON oa.land_id_2 = l2.id
            JOIN users u1 ON l1.user_id = u1.id
            JOIN users u2 ON l2.user_id = u2.id
            WHERE oa.land_id_1 = $landId OR oa.land_id_2 = $landId
            ORDER BY oa.created_at DESC";

    $result = mysqli_query($conn, $sql);
    $alerts = [];

    while ($row = mysqli_fetch_assoc($result)) {
        $alerts[] = $row;
    }

    return $alerts;
}

/**
 * Record an overlap attempt for admin review
 * This tracks when someone tries to add land that overlaps with existing parcels
 * @param mysqli $conn Database connection
 * @param int $newLandId ID of the new land (may be null if land wasn't saved)
 * @param string $newLandName Name of the new land
 * @param array $overlap Single overlap entry from detectLandOverlaps
 * @param array $attemptedBy User info ['id', 'name', 'phone', 'email']
 * @param array $locationInfo Optional location info ['region', 'district']
 */
function recordOverlapAttempt($conn, $newLandId, $newLandName, $overlap, $attemptedBy, $locationInfo = []) {
    // Get existing land owner info
    $existingLandId = $overlap['land_id'];
    $existingLandName = mysqli_real_escape_string($conn, $overlap['land_name']);
    $existingOwnerId = $overlap['owner_id'];
    $existingOwnerName = mysqli_real_escape_string($conn, $overlap['owner_name']);

    // Get owner phone from users table
    $ownerPhoneResult = mysqli_query($conn, "SELECT phone FROM users WHERE id = $existingOwnerId");
    $existingOwnerPhone = '';
    if ($ownerRow = mysqli_fetch_assoc($ownerPhoneResult)) {
        $existingOwnerPhone = mysqli_real_escape_string($conn, $ownerRow['phone'] ?? '');
    }

    // Attempted by info
    $attemptedByUserId = isset($attemptedBy['id']) ? intval($attemptedBy['id']) : 'NULL';
    $attemptedByName = mysqli_real_escape_string($conn, $attemptedBy['name'] ?? '');
    $attemptedByPhone = mysqli_real_escape_string($conn, $attemptedBy['phone'] ?? '');
    $attemptedByEmail = mysqli_real_escape_string($conn, $attemptedBy['email'] ?? '');

    // New land info
    $newLandIdSql = $newLandId ? intval($newLandId) : 'NULL';
    $newLandNameEsc = mysqli_real_escape_string($conn, $newLandName);

    // Overlap details
    $overlapType = mysqli_real_escape_string($conn, $overlap['overlap_type']);
    $overlapPercentage = isset($overlap['details']['overlap_percentage'])
        ? floatval($overlap['details']['overlap_percentage'])
        : 0;
    $overlapDescription = mysqli_real_escape_string($conn, $overlap['details']['description']);
    $severity = mysqli_real_escape_string($conn, $overlap['details']['severity']);

    // Location info
    $region = mysqli_real_escape_string($conn, $locationInfo['region'] ?? '');
    $district = mysqli_real_escape_string($conn, $locationInfo['district'] ?? '');

    // Request info
    $ipAddress = mysqli_real_escape_string($conn, $_SERVER['REMOTE_ADDR'] ?? '');
    $userAgent = mysqli_real_escape_string($conn, $_SERVER['HTTP_USER_AGENT'] ?? '');

    $sql = "INSERT INTO overlap_attempts (
                attempted_by_user_id, attempted_by_user_name, attempted_by_phone, attempted_by_email,
                new_land_id, new_land_name,
                existing_land_id, existing_land_name, existing_land_owner_id, existing_land_owner_name, existing_land_owner_phone,
                overlap_type, overlap_percentage, overlap_description, severity,
                region, district, ip_address, user_agent
            ) VALUES (
                $attemptedByUserId, '$attemptedByName', '$attemptedByPhone', '$attemptedByEmail',
                $newLandIdSql, '$newLandNameEsc',
                $existingLandId, '$existingLandName', $existingOwnerId, '$existingOwnerName', '$existingOwnerPhone',
                '$overlapType', $overlapPercentage, '$overlapDescription', '$severity',
                '$region', '$district', '$ipAddress', '$userAgent'
            )";

    mysqli_query($conn, $sql);

    // Log activity
    $logDesc = "Overlap attempt detected: '$newLandNameEsc' overlaps with '$existingLandName' (Owner: $existingOwnerName)";
    mysqli_query($conn, "INSERT INTO activity_logs (user_id, action, description, ip_address)
                         VALUES ($attemptedByUserId, 'overlap_attempt', '$logDesc', '$ipAddress')");
}

/**
 * Save overlap alerts and record attempts for admin review
 * @param mysqli $conn
 * @param int $newLandId
 * @param string $newLandName
 * @param array $overlaps Array from detectLandOverlaps
 * @param array $attemptedBy User info ['id', 'name', 'phone', 'email']
 * @param array $locationInfo Optional location info ['region', 'district']
 */
function saveOverlapAlertsWithTracking($conn, $newLandId, $newLandName, $overlaps, $attemptedBy, $locationInfo = []) {
    foreach ($overlaps as $overlap) {
        // Save the regular overlap alert
        $landId2 = $overlap['land_id'];
        $overlapType = mysqli_real_escape_string($conn, $overlap['overlap_type']);
        $description = mysqli_real_escape_string($conn, $overlap['details']['description']);

        $overlapPercentage = isset($overlap['details']['overlap_percentage'])
            ? floatval($overlap['details']['overlap_percentage'])
            : 100;

        $alertMessage = $description;
        if (isset($overlap['details']['overlap_area_sqm'])) {
            $alertMessage .= " (Approx. {$overlap['details']['overlap_area_sqm']} sqm overlap)";
        }

        $sql = "INSERT INTO overlap_alerts (land_id_1, land_id_2, overlap_percentage, alert_message, status)
                VALUES ($newLandId, $landId2, $overlapPercentage, '$alertMessage', 'pending')";
        mysqli_query($conn, $sql);

        // Also record the attempt for admin tracking
        recordOverlapAttempt($conn, $newLandId, $newLandName, $overlap, $attemptedBy, $locationInfo);
    }
}

/**
 * Get pending overlap attempts for admin review
 * @param mysqli $conn
 * @param string $status Filter by status (null for all)
 * @param int $limit
 * @param int $offset
 * @return array
 */
function getOverlapAttempts($conn, $status = null, $limit = 20, $offset = 0) {
    $whereClause = $status ? "WHERE review_status = '" . mysqli_real_escape_string($conn, $status) . "'" : "";

    $sql = "SELECT oa.*,
                   l.land_name as new_land_current_name,
                   el.land_name as existing_land_current_name
            FROM overlap_attempts oa
            LEFT JOIN lands l ON oa.new_land_id = l.id
            LEFT JOIN lands el ON oa.existing_land_id = el.id
            $whereClause
            ORDER BY
                CASE oa.severity
                    WHEN 'critical' THEN 1
                    WHEN 'warning' THEN 2
                    ELSE 3
                END,
                oa.created_at DESC
            LIMIT $limit OFFSET $offset";

    $result = mysqli_query($conn, $sql);
    $attempts = [];

    while ($row = mysqli_fetch_assoc($result)) {
        $attempts[] = $row;
    }

    return $attempts;
}

/**
 * Count overlap attempts by status
 * @param mysqli $conn
 * @param string $status Optional status filter
 * @return int
 */
function countOverlapAttempts($conn, $status = null) {
    $whereClause = $status ? "WHERE review_status = '" . mysqli_real_escape_string($conn, $status) . "'" : "";
    $result = mysqli_query($conn, "SELECT COUNT(*) as cnt FROM overlap_attempts $whereClause");
    $row = mysqli_fetch_assoc($result);
    return intval($row['cnt']);
}

/**
 * Mark overlap attempt as reviewed
 * @param mysqli $conn
 * @param int $attemptId
 * @param int $reviewedBy Admin user ID
 * @param string $status 'reviewed', 'flagged', or 'cleared'
 * @param string $notes Review notes
 */
function reviewOverlapAttempt($conn, $attemptId, $reviewedBy, $status, $notes = '') {
    $attemptId = intval($attemptId);
    $reviewedBy = intval($reviewedBy);
    $status = mysqli_real_escape_string($conn, $status);
    $notes = mysqli_real_escape_string($conn, $notes);

    $sql = "UPDATE overlap_attempts
            SET reviewed_by = $reviewedBy,
                review_status = '$status',
                review_notes = '$notes',
                reviewed_at = NOW()
            WHERE id = $attemptId";

    return mysqli_query($conn, $sql);
}

/**
 * Calculate distance between two points in meters using Haversine formula
 * @param array $point1 ['lat' => float, 'lng' => float]
 * @param array $point2 ['lat' => float, 'lng' => float]
 * @return float Distance in meters
 */
function calculateDistanceMeters($point1, $point2) {
    $earthRadius = 6371000; // meters

    $lat1 = deg2rad($point1['lat']);
    $lat2 = deg2rad($point2['lat']);
    $deltaLat = deg2rad($point2['lat'] - $point1['lat']);
    $deltaLng = deg2rad($point2['lng'] - $point1['lng']);

    $a = sin($deltaLat / 2) * sin($deltaLat / 2) +
         cos($lat1) * cos($lat2) *
         sin($deltaLng / 2) * sin($deltaLng / 2);

    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $earthRadius * $c;
}

/**
 * Calculate the centroid (center point) of a polygon
 * @param array $polygon Array of points
 * @return array ['lat' => float, 'lng' => float]
 */
function calculatePolygonCentroid($polygon) {
    $n = count($polygon);
    if ($n == 0) return ['lat' => 0, 'lng' => 0];

    $sumLat = 0;
    $sumLng = 0;

    foreach ($polygon as $point) {
        $sumLat += $point['lat'];
        $sumLng += $point['lng'];
    }

    return [
        'lat' => $sumLat / $n,
        'lng' => $sumLng / $n
    ];
}

/**
 * Determine the direction of polygon2 relative to polygon1
 * @param array $polygon1 The reference polygon
 * @param array $polygon2 The other polygon
 * @return string Direction (north, south, east, west, northeast, etc.)
 */
function determineRelativeDirection($polygon1, $polygon2) {
    $center1 = calculatePolygonCentroid($polygon1);
    $center2 = calculatePolygonCentroid($polygon2);

    $latDiff = $center2['lat'] - $center1['lat'];
    $lngDiff = $center2['lng'] - $center1['lng'];

    // Determine primary direction based on angle
    $angle = atan2($latDiff, $lngDiff) * 180 / M_PI;

    // Convert angle to compass direction
    // 0° = East, 90° = North, 180° = West, -90° = South
    if ($angle >= -22.5 && $angle < 22.5) return 'east';
    if ($angle >= 22.5 && $angle < 67.5) return 'northeast';
    if ($angle >= 67.5 && $angle < 112.5) return 'north';
    if ($angle >= 112.5 && $angle < 157.5) return 'northwest';
    if ($angle >= 157.5 || $angle < -157.5) return 'west';
    if ($angle >= -157.5 && $angle < -112.5) return 'southwest';
    if ($angle >= -112.5 && $angle < -67.5) return 'south';
    if ($angle >= -67.5 && $angle < -22.5) return 'southeast';

    return 'north'; // Default
}

/**
 * Find the minimum distance between two polygons (closest points)
 * @param array $polygon1 First polygon
 * @param array $polygon2 Second polygon
 * @return float Minimum distance in meters
 */
function minimumPolygonDistance($polygon1, $polygon2) {
    $minDistance = PHP_FLOAT_MAX;

    foreach ($polygon1 as $p1) {
        foreach ($polygon2 as $p2) {
            $dist = calculateDistanceMeters($p1, $p2);
            if ($dist < $minDistance) {
                $minDistance = $dist;
            }
        }
    }

    return $minDistance;
}

/**
 * Auto-detect neighbors for a land parcel
 * Finds overlapping lands and nearby lands within buffer distance
 * @param mysqli $conn Database connection
 * @param int $landId The land to find neighbors for
 * @param array $landPoints Array of points for the land
 * @param float $bufferMeters Distance in meters to consider as "nearby" (default 50m)
 * @return array Array of detected neighbors with details
 */
function detectNeighbors($conn, $landId, $landPoints, $bufferMeters = 50) {
    $neighbors = [];
    $landId = intval($landId);

    // Check which columns exist in lands table
    $landColumns = [];
    $colResult = mysqli_query($conn, "SHOW COLUMNS FROM lands");
    if ($colResult) {
        while ($col = mysqli_fetch_assoc($colResult)) {
            $landColumns[] = strtolower($col['Field']);
        }
    }

    $hasVillageId = in_array('village_id', $landColumns);
    $hasStatus = in_array('status', $landColumns);

    // Get land's village_id for filtering (if column exists)
    $villageId = null;
    if ($hasVillageId) {
        $landResult = mysqli_query($conn, "SELECT village_id FROM lands WHERE id = $landId");
        if ($landResult) {
            $landData = mysqli_fetch_assoc($landResult);
            $villageId = $landData['village_id'] ?? null;
        }
    }

    // Build WHERE clause dynamically
    $whereClause = "l.id != $landId";
    if ($hasStatus) {
        $whereClause .= " AND (l.status IS NULL OR l.status NOT IN ('rejected', 'deleted'))";
    }

    // Build SELECT clause dynamically
    $selectParts = ["l.id", "l.land_name", "l.user_id"];
    if ($hasVillageId) {
        $selectParts[] = "l.village_id";
    }
    $selectParts[] = "u.full_name as owner_name";
    $selectParts[] = "u.username";
    $selectParts[] = "u.phone as owner_phone";

    $selectClause = implode(", ", $selectParts);

    // Get all other lands with their beacon points
    $sql = "SELECT $selectClause
            FROM lands l
            JOIN users u ON l.user_id = u.id
            WHERE $whereClause";

    $landsResult = mysqli_query($conn, $sql);

    // Normalize land points format
    $newPolygon = [];
    foreach ($landPoints as $p) {
        $newPolygon[] = [
            'lat' => floatval($p['lat'] ?? $p['latitude'] ?? 0),
            'lng' => floatval($p['lng'] ?? $p['longitude'] ?? 0)
        ];
    }

    if (count($newPolygon) < 3) return $neighbors;

    while ($land = mysqli_fetch_assoc($landsResult)) {
        // Get beacon points for this land
        $pointsSql = "SELECT latitude, longitude FROM beacon_points
                      WHERE land_id = {$land['id']} ORDER BY point_order";
        $pointsResult = mysqli_query($conn, $pointsSql);

        $existingPoints = [];
        while ($p = mysqli_fetch_assoc($pointsResult)) {
            $existingPoints[] = [
                'lat' => floatval($p['latitude']),
                'lng' => floatval($p['longitude'])
            ];
        }

        if (count($existingPoints) < 3) continue;

        // Check for various types of relationships
        $isNeighbor = false;
        $neighborType = null;
        $overlapPercentage = null;
        $distance = null;

        // 1. Check if polygons overlap
        if (doPolygonsIntersect($newPolygon, $existingPoints)) {
            $isNeighbor = true;
            $neighborType = 'overlapping';
            $overlapArea = calculateOverlapArea($newPolygon, $existingPoints);
            $newArea = calculatePolygonAreaMeters($newPolygon);
            $overlapPercentage = $newArea > 0 ? ($overlapArea / $newArea) * 100 : 0;
            $distance = 0;
        }
        // 2. Check if one is inside the other
        elseif (isPolygonInsidePolygon($newPolygon, $existingPoints) ||
                isPolygonInsidePolygon($existingPoints, $newPolygon)) {
            $isNeighbor = true;
            $neighborType = 'contained';
            $overlapPercentage = 100;
            $distance = 0;
        }
        // 3. Check if nearby (within buffer distance)
        else {
            $distance = minimumPolygonDistance($newPolygon, $existingPoints);
            if ($distance <= $bufferMeters) {
                $isNeighbor = true;
                $neighborType = 'nearby';
                $overlapPercentage = 0;
            }
        }

        if ($isNeighbor) {
            // Determine direction
            $direction = determineRelativeDirection($newPolygon, $existingPoints);

            $landVillageId = isset($land['village_id']) ? $land['village_id'] : null;

            $neighbors[] = [
                'land_id' => $land['id'],
                'land_name' => $land['land_name'],
                'user_id' => $land['user_id'],
                'owner_name' => $land['owner_name'] ?: $land['username'],
                'owner_phone' => $land['owner_phone'],
                'village_id' => $landVillageId,
                'same_village' => ($villageId && $landVillageId && $landVillageId == $villageId),
                'neighbor_type' => $neighborType,
                'direction' => $direction,
                'overlap_percentage' => $overlapPercentage !== null ? round($overlapPercentage, 2) : null,
                'distance_meters' => $distance !== null ? round($distance, 2) : null
            ];
        }
    }

    // Sort by distance (overlapping first, then nearest)
    usort($neighbors, function($a, $b) {
        if ($a['distance_meters'] === null) return -1;
        if ($b['distance_meters'] === null) return 1;
        return $a['distance_meters'] - $b['distance_meters'];
    });

    return $neighbors;
}

/**
 * Save auto-detected neighbors to the database
 * @param mysqli $conn Database connection
 * @param int $landId The land ID
 * @param array $neighbors Array from detectNeighbors()
 * @param bool $notifyNeighbors Whether to create notifications
 * @return int Number of neighbors saved
 */
function saveDetectedNeighbors($conn, $landId, $neighbors, $notifyNeighbors = true) {
    $landId = intval($landId);
    $savedCount = 0;

    foreach ($neighbors as $neighbor) {
        // Check if this neighbor relationship already exists
        $checkSql = "SELECT id FROM land_neighbors
                     WHERE land_id = $landId AND neighbor_land_id = {$neighbor['land_id']}";
        $existing = mysqli_query($conn, $checkSql);

        if (mysqli_num_rows($existing) > 0) continue; // Skip if already exists

        // Generate confirmation code
        $confirmationCode = strtoupper(substr(md5(uniqid()), 0, 8));

        // Calculate expiry (14 days from now)
        $expiresAt = date('Y-m-d H:i:s', strtotime('+14 days'));

        // Escape values
        $neighborName = mysqli_real_escape_string($conn, $neighbor['owner_name']);
        $neighborPhone = mysqli_real_escape_string($conn, $neighbor['owner_phone'] ?? '');
        $direction = mysqli_real_escape_string($conn, $neighbor['direction']);
        $overlapPct = $neighbor['overlap_percentage'] !== null ? $neighbor['overlap_percentage'] : 'NULL';
        $distanceM = $neighbor['distance_meters'] !== null ? $neighbor['distance_meters'] : 'NULL';
        $neighborUserId = $neighbor['user_id'] ? intval($neighbor['user_id']) : 'NULL';
        $neighborLandId = intval($neighbor['land_id']);

        $sql = "INSERT INTO land_neighbors (
                    land_id, neighbor_land_id, neighbor_user_id,
                    neighbor_name, neighbor_phone, neighbor_direction,
                    detection_method, overlap_percentage, distance_meters,
                    confirmation_status, confirmation_code, expires_at, created_at
                ) VALUES (
                    $landId, $neighborLandId, $neighborUserId,
                    '$neighborName', '$neighborPhone', '$direction',
                    'auto', $overlapPct, $distanceM,
                    'pending', '$confirmationCode', '$expiresAt', NOW()
                )";

        if (mysqli_query($conn, $sql)) {
            $savedCount++;

            // Create notification for the neighbor user
            if ($notifyNeighbors && $neighbor['user_id']) {
                // Get land name
                $landResult = mysqli_query($conn, "SELECT land_name FROM lands WHERE id = $landId");
                $landData = mysqli_fetch_assoc($landResult);
                $landName = $landData['land_name'] ?? 'Unknown';

                $notifSql = "INSERT INTO cbc_notifications (
                    user_id, notification_type, title, message, land_id, created_at
                ) VALUES (
                    {$neighbor['user_id']}, 'neighbor_confirmation',
                    'Neighbor Confirmation Request',
                    'You have been identified as a neighbor for land \"$landName\". Please confirm the boundary.',
                    $landId, NOW()
                )";
                mysqli_query($conn, $notifSql);
            }
        }
    }

    // Update land's neighbor count
    mysqli_query($conn, "UPDATE lands SET neighbor_required_count = GREATEST(2, $savedCount) WHERE id = $landId");

    return $savedCount;
}

/**
 * Get neighbors for a land parcel
 * @param mysqli $conn Database connection
 * @param int $landId The land ID
 * @return array Array of neighbor records
 */
function getLandNeighbors($conn, $landId) {
    $landId = intval($landId);
    $neighbors = [];

    // Check if land_neighbors table exists
    $tableCheck = mysqli_query($conn, "SHOW TABLES LIKE 'land_neighbors'");
    if (!$tableCheck || mysqli_num_rows($tableCheck) == 0) {
        return $neighbors; // Table doesn't exist, return empty array
    }

    // Check which columns exist in land_neighbors table
    $lnColumns = [];
    $colResult = mysqli_query($conn, "SHOW COLUMNS FROM land_neighbors");
    if ($colResult) {
        while ($col = mysqli_fetch_assoc($colResult)) {
            $lnColumns[] = strtolower($col['Field']);
        }
    }

    $hasConfirmedBy = in_array('confirmed_by_village_official', $lnColumns);
    $hasNeighborLandId = in_array('neighbor_land_id', $lnColumns);
    $hasNeighborUserId = in_array('neighbor_user_id', $lnColumns);
    $hasNeighborDirection = in_array('neighbor_direction', $lnColumns);

    // Build dynamic SELECT clause
    $selectParts = ["ln.*"];
    $joinParts = "";

    if ($hasNeighborLandId) {
        $selectParts[] = "l.land_name as neighbor_land_name";
        $joinParts .= " LEFT JOIN lands l ON ln.neighbor_land_id = l.id";
    }
    if ($hasNeighborUserId) {
        $selectParts[] = "u.full_name as neighbor_user_name";
        $selectParts[] = "u.phone as neighbor_user_phone";
        $joinParts .= " LEFT JOIN users u ON ln.neighbor_user_id = u.id";
    }
    if ($hasConfirmedBy) {
        $selectParts[] = "cu.full_name as confirmed_by_name";
        $joinParts .= " LEFT JOIN users cu ON ln.confirmed_by_village_official = cu.id";
    }

    $selectClause = implode(", ", $selectParts);
    $orderBy = $hasNeighborDirection ? "ORDER BY ln.neighbor_direction" : "";

    $sql = "SELECT $selectClause FROM land_neighbors ln $joinParts WHERE ln.land_id = $landId $orderBy";

    $result = mysqli_query($conn, $sql);
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $neighbors[] = $row;
        }
    }

    return $neighbors;
}
?>
