<?php
declare(strict_types=1);
require_once '../config/database.php';
require_once '../app/helpers/rbac.php';
require_once '../app/helpers/audit.php';
require_once '../app/helpers/api_security.php';

header('Content-Type: application/json');

requireApiLogin();
enforceCsrfForUnsafeRequest();

$action = $_GET['action'] ?? '';

try {
    switch ($action) {
        case 'live':
            handleLive($pdo);
            break;
        case 'vehicle':
            handleVehicle($pdo);
            break;
        case 'route':
            handleRoute($pdo);
            break;
        case 'update':
            handleUpdate($pdo);
            break;
        case 'geofence_list':
            handleGeofenceList($pdo);
            break;
        case 'geofence_save':
            handleGeofenceSave($pdo);
            break;
        case 'geofence_delete':
            handleGeofenceDelete($pdo);
            break;
        case 'geofence_events':
            handleGeofenceEvents($pdo);
            break;
        case 'idle':
            handleIdle($pdo);
            break;
        case 'tracked_vehicles':
            handleTrackedVehicles($pdo);
            break;
        default:
            respond(['status' => 'error', 'message' => 'Invalid action']);
    }
} catch (Throwable $e) {
    respond(['status' => 'error', 'message' => $e->getMessage()]);
}

function respond(array $payload): void { apiRespond($payload); }

function handleLive(PDO $pdo): void
{
    if (!isAdmin() && !can('gps_tracking.view')) {
        respond(['status' => 'error', 'message' => 'Unauthorized']);
    }

    $stmt = $pdo->query("
        SELECT
            v.id AS vehicle_id,
            v.plate_number,
            v.vehicle_model,
            v.vehicle_type,
            v.vehicle_status,
            g.latitude,
            g.longitude,
            g.speed_kmh,
            g.heading,
            g.ignition,
            g.recorded_at,
            dm.tracker_device_id,
            d.full_name AS driver_name
        FROM vehicles v
        INNER JOIN tracker_device_mappings dm ON dm.vehicle_id = v.id
        INNER JOIN tracker_integrations ti ON ti.id = dm.integration_id AND ti.status = 'active' AND ti.deleted_at IS NULL
        LEFT JOIN gps_locations g ON g.vehicle_id = v.id
            AND g.id = (SELECT MAX(g2.id) FROM gps_locations g2 WHERE g2.vehicle_id = v.id)
        LEFT JOIN vehicle_assignments va ON va.vehicle_id = v.id AND va.deleted_at IS NULL AND va.assignment_end IS NULL
        LEFT JOIN drivers d ON d.id = va.driver_id
        WHERE v.deleted_at IS NULL
        ORDER BY v.plate_number
    ");
    $vehicles = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $vehiclesOnMap = [];
    $idleThreshold = (int)($_GET['idle_minutes'] ?? 30);

    foreach ($vehicles as &$v) {
        $v['has_position'] = $v['latitude'] !== null && $v['longitude'] !== null;
        if ($v['has_position']) {
            $v['latitude'] = (float)$v['latitude'];
            $v['longitude'] = (float)$v['longitude'];
            $v['speed_kmh'] = (float)($v['speed_kmh'] ?? 0);
            $v['heading'] = (float)($v['heading'] ?? 0);

            if ($v['recorded_at']) {
                $minutesSince = (time() - strtotime($v['recorded_at'])) / 60;
                $v['is_idle'] = $v['speed_kmh'] < 1 && $minutesSince >= 5;
                $v['is_offline'] = $minutesSince > 30;
                $v['minutes_since_update'] = round($minutesSince, 1);
            } else {
                $v['is_idle'] = false;
                $v['is_offline'] = true;
                $v['minutes_since_update'] = null;
            }

            $vehiclesOnMap[] = $v;
        }
    }
    unset($v);

    respond(['status' => 'success', 'data' => $vehiclesOnMap, 'total_tracked' => count($vehicles), 'with_position' => count($vehiclesOnMap)]);
}

function handleVehicle(PDO $pdo): void
{
    $vehicleId = (int)($_GET['vehicle_id'] ?? 0);
    if ($vehicleId <= 0) respond(['status' => 'error', 'message' => 'Vehicle ID required']);

    $stmt = $pdo->prepare("
        SELECT g.*, v.plate_number, v.vehicle_model
        FROM gps_locations g
        JOIN vehicles v ON v.id = g.vehicle_id
        WHERE g.vehicle_id = ?
        ORDER BY g.recorded_at DESC
        LIMIT 100
    ");
    $stmt->execute([$vehicleId]);
    $locations = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($locations as &$loc) {
        $loc['latitude'] = (float)$loc['latitude'];
        $loc['longitude'] = (float)$loc['longitude'];
    }
    unset($loc);

    respond(['status' => 'success', 'data' => $locations]);
}

function handleRoute(PDO $pdo): void
{
    $vehicleId = (int)($_GET['vehicle_id'] ?? 0);
    $dateFrom = $_GET['date_from'] ?? date('Y-m-d', strtotime('-1 day'));
    $dateTo = $_GET['date_to'] ?? date('Y-m-d');

    if ($vehicleId <= 0) respond(['status' => 'error', 'message' => 'Vehicle ID required']);

    $stmt = $pdo->prepare("
        SELECT latitude, longitude, speed_kmh, heading, recorded_at
        FROM gps_locations
        WHERE vehicle_id = ?
          AND recorded_at >= ? AND recorded_at <= ?
        ORDER BY recorded_at ASC
    ");
    $stmt->execute([$vehicleId, $dateFrom . ' 00:00:00', $dateTo . ' 23:59:59']);
    $points = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($points as &$p) {
        $p['latitude'] = (float)$p['latitude'];
        $p['longitude'] = (float)$p['longitude'];
        $p['speed_kmh'] = (float)($p['speed_kmh'] ?? 0);
    }
    unset($p);

    respond(['status' => 'success', 'data' => $points, 'count' => count($points)]);
}

function handleUpdate(PDO $pdo): void
{
    $apiKey = $_SERVER['HTTP_X_API_KEY'] ?? ($_GET['api_key'] ?? '');
    $isApi = !empty($apiKey);

    if (!$isApi && !isAdmin() && !can('gps_tracking.api')) {
        respond(['status' => 'error', 'message' => 'Unauthorized. Provide X-API-Key header or valid session.']);
    }

    if ($isApi) {
        $keyStmt = $pdo->prepare("SELECT id FROM tracker_integrations WHERE api_key = ? AND status = 'active' AND deleted_at IS NULL LIMIT 1");
        $keyStmt->execute([$apiKey]);
        if (!$keyStmt->fetch()) {
            respond(['status' => 'error', 'message' => 'Invalid API key']);
        }
    }

    $latitude = (float)($_POST['latitude'] ?? 0);
    $longitude = (float)($_POST['longitude'] ?? 0);
    $vehicleId = !empty($_POST['vehicle_id']) ? (int)$_POST['vehicle_id'] : null;
    $trackerDeviceId = trim($_POST['tracker_device_id'] ?? ($_GET['device_id'] ?? ''));
    $speed = (float)($_POST['speed_kmh'] ?? 0);
    $heading = (float)($_POST['heading'] ?? 0);
    $altitude = (int)($_POST['altitude'] ?? 0);
    $accuracy = (int)($_POST['accuracy'] ?? 0);
    $ignition = isset($_POST['ignition']) ? (int)$_POST['ignition'] : null;
    $recordedAt = $_POST['recorded_at'] ?? date('Y-m-d H:i:s');

    if ($latitude == 0 && $longitude == 0) {
        respond(['status' => 'error', 'message' => 'Invalid coordinates']);
    }

    // If only tracker_device_id provided, look up vehicle mapping
    if (!$vehicleId && $trackerDeviceId) {
        $mapStmt = $pdo->prepare("SELECT vehicle_id FROM tracker_device_mappings WHERE tracker_device_id = ? LIMIT 1");
        $mapStmt->execute([$trackerDeviceId]);
        $mapped = $mapStmt->fetchColumn();
        if ($mapped) $vehicleId = (int)$mapped;
    }

    $stmt = $pdo->prepare("
        INSERT INTO gps_locations (vehicle_id, tracker_device_id, latitude, longitude, speed_kmh, heading, altitude, accuracy, ignition, recorded_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ");
    $stmt->execute([$vehicleId, $trackerDeviceId ?: null, $latitude, $longitude, $speed, $heading, $altitude, $accuracy, $ignition, $recordedAt]);

    respond(['status' => 'success', 'message' => 'Position recorded', 'id' => (int)$pdo->lastInsertId()]);
}

function handleGeofenceList(PDO $pdo): void
{
    $stmt = $pdo->query("SELECT * FROM geofence_zones WHERE deleted_at IS NULL ORDER BY name ASC");
    $zones = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($zones as &$z) {
        $z['center_lat'] = $z['center_lat'] ? (float)$z['center_lat'] : null;
        $z['center_lng'] = $z['center_lng'] ? (float)$z['center_lng'] : null;
        if ($z['polygon_data']) $z['polygon_data'] = json_decode($z['polygon_data'], true);
        if ($z['geojson']) $z['geojson'] = json_decode($z['geojson'], true);
    }
    unset($z);

    respond(['status' => 'success', 'data' => $zones]);
}

function handleGeofenceSave(PDO $pdo): void
{
    if (!isAdmin() && !can('gps_tracking.geofence')) {
        respond(['status' => 'error', 'message' => 'Unauthorized']);
    }

    $id = (int)($_POST['id'] ?? 0);
    $name = trim($_POST['name'] ?? '');
    if (!$name) respond(['status' => 'error', 'message' => 'Geofence name is required']);

    $polygonData = $_POST['polygon_data'] ?? null;
    if ($polygonData && is_string($polygonData)) {
        $decoded = json_decode($polygonData, true);
        if ($decoded === null) respond(['status' => 'error', 'message' => 'Invalid polygon data JSON']);
        $polygonData = $decoded;
    }

    $data = [
        'name' => $name,
        'description' => trim($_POST['description'] ?? ''),
        'zone_type' => $_POST['zone_type'] ?? 'circle',
        'center_lat' => !empty($_POST['center_lat']) ? (float)$_POST['center_lat'] : null,
        'center_lng' => !empty($_POST['center_lng']) ? (float)$_POST['center_lng'] : null,
        'radius_meters' => (int)($_POST['radius_meters'] ?? 100),
        'polygon_data' => $polygonData ? json_encode($polygonData) : null,
        'geojson' => $_POST['geojson'] ?? null,
        'color' => trim($_POST['color'] ?? '#3388ff'),
        'is_active' => (int)($_POST['is_active'] ?? 1),
    ];

    if ($id > 0) {
        $sets = implode(', ', array_map(fn($c) => "{$c} = :{$c}", array_keys($data)));
        $data['id'] = $id;
        $pdo->prepare("UPDATE geofence_zones SET {$sets} WHERE id = :id")->execute($data);
        respond(['status' => 'success', 'message' => 'Geofence updated']);
    } else {
        $cols = implode(', ', array_keys($data));
        $vals = ':' . implode(', :', array_keys($data));
        $pdo->prepare("INSERT INTO geofence_zones ({$cols}) VALUES ({$vals})")->execute($data);
        respond(['status' => 'success', 'message' => 'Geofence created', 'id' => (int)$pdo->lastInsertId()]);
    }
}

function handleGeofenceDelete(PDO $pdo): void
{
    if (!isAdmin() && !can('gps_tracking.geofence')) {
        respond(['status' => 'error', 'message' => 'Unauthorized']);
    }

    $id = (int)($_POST['id'] ?? 0);
    if ($id <= 0) respond(['status' => 'error', 'message' => 'Invalid ID']);

    $pdo->prepare("UPDATE geofence_zones SET deleted_at = NOW() WHERE id = ?")->execute([$id]);
    respond(['status' => 'success', 'message' => 'Geofence deleted']);
}

function handleGeofenceEvents(PDO $pdo): void
{
    $geofenceId = !empty($_GET['geofence_id']) ? (int)$_GET['geofence_id'] : null;
    $vehicleId = !empty($_GET['vehicle_id']) ? (int)$_GET['vehicle_id'] : null;
    $limit = min((int)($_GET['limit'] ?? 50), 200);

    $where = [];
    $params = [];
    if ($geofenceId) { $where[] = 'ge.id = ?'; $params[] = $geofenceId; }
    if ($vehicleId) { $where[] = 'ge.vehicle_id = ?'; $params[] = $vehicleId; }

    $sql = "
        SELECT ge.*, gz.name AS geofence_name, v.plate_number
        FROM geofence_events ge
        JOIN geofence_zones gz ON gz.id = ge.geofence_id
        LEFT JOIN vehicles v ON v.id = ge.vehicle_id
    ";
    if ($where) $sql .= ' WHERE ' . implode(' AND ', $where);
    $sql .= " ORDER BY ge.event_at DESC LIMIT {$limit}";

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}

function handleIdle(PDO $pdo): void
{
    $thresholdMinutes = (int)($_GET['threshold'] ?? 30);

    $stmt = $pdo->prepare("
        SELECT
            g.vehicle_id,
            v.plate_number,
            v.vehicle_model,
            g.latitude,
            g.longitude,
            g.speed_kmh,
            g.recorded_at,
            TIMESTAMPDIFF(MINUTE, g.recorded_at, NOW()) AS idle_minutes,
            d.full_name AS driver_name
        FROM gps_locations g
        JOIN vehicles v ON v.id = g.vehicle_id
        LEFT JOIN vehicle_assignments va ON va.vehicle_id = v.id AND va.deleted_at IS NULL AND va.assignment_end IS NULL
        LEFT JOIN drivers d ON d.id = va.driver_id
        WHERE g.id IN (
            SELECT MAX(g2.id) FROM gps_locations g2 GROUP BY g2.vehicle_id
        )
        AND g.speed_kmh < 1
        AND TIMESTAMPDIFF(MINUTE, g.recorded_at, NOW()) >= ?
        ORDER BY idle_minutes DESC
    ");
    $stmt->execute([$thresholdMinutes]);
    $idle = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($idle as &$v) {
        $v['latitude'] = (float)$v['latitude'];
        $v['longitude'] = (float)$v['longitude'];
    }
    unset($v);

    respond(['status' => 'success', 'data' => $idle, 'count' => count($idle)]);
}

function handleTrackedVehicles(PDO $pdo): void
{
    $stmt = $pdo->query("
        SELECT DISTINCT v.id, v.plate_number, v.vehicle_model, v.vehicle_type
        FROM vehicles v
        INNER JOIN tracker_device_mappings dm ON dm.vehicle_id = v.id
        WHERE v.deleted_at IS NULL
        ORDER BY v.plate_number
    ");
    respond(['status' => 'success', 'data' => $stmt->fetchAll()]);
}
