<?php
/**
 * Sistema de Rastreamento em Tempo Real
 * Implementa WebSocket para atualizações instantâneas de velocidade, quilometragem e mapa
 */

// Configurar UTF-8 e CORS
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

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

// Conectar ao banco
function conectarBanco() {
    $host = 'localhost';
    $dbname = 'pinheir3_controle_frotasV1.1';
    $username = 'pinheir3_admin';
    $password = '080880Gelboy';
    
    try {
        $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password, [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
        return $pdo;
    } catch (PDOException $e) {
        throw new Exception('Erro de conexão: ' . $e->getMessage());
    }
}

// 🔧 CORREÇÃO: Função Haversine para calcular distância em METROS
function haversine($lat1, $lon1, $lat2, $lon2) {
    $R = 6371000.0; // 🔧 CORREÇÃO: Raio da Terra em METROS (não km)
    $dLat = deg2rad($lat2 - $lat1);
    $dLon = deg2rad($lon2 - $lon1);
    $lat1 = deg2rad($lat1);
    $lat2 = deg2rad($lat2);
    
    $a = sin($dLat/2) * sin($dLat/2) + cos($lat1) * cos($lat2) * sin($dLon/2) * sin($dLon/2);
    $c = 2 * atan2(sqrt($a), sqrt(1-$a));
    return $R * $c;
}

// Resposta padronizada
function resposta($sucesso, $dados = null, $mensagem = '', $codigo = 200) {
    http_response_code($codigo);
    echo json_encode([
        'sucesso' => $sucesso,
        'dados' => $dados,
        'mensagem' => $mensagem,
        'timestamp' => date('c')
    ], JSON_UNESCAPED_UNICODE);
    exit();
}

// Classe para gerenciar estado de rastreamento em tempo real
class RealtimeTracker {
    private $pdo;
    private $trackingData = [];
    
    public function __construct($pdo) {
        $this->pdo = $pdo;
    }
    
    /**
     * Atualiza posição GPS em tempo real
     */
    public function atualizarPosicao($viagemId, $latitude, $longitude, $velocidade = null, $precisao = null) {
        try {
            // Buscar dados atuais da viagem
            $stmt = $this->pdo->prepare("
                SELECT v.*, m.nome as motorista_nome, ve.modelo as veiculo_modelo, ve.placa as veiculo_placa
                FROM viagens v
                LEFT JOIN motoristas m ON v.tecnico_id = m.id
                LEFT JOIN veiculos ve ON v.veiculo_id = ve.id
                WHERE v.id = ?
            ");
            $stmt->execute([$viagemId]);
            $viagem = $stmt->fetch();
            
            if (!$viagem) {
                throw new Exception('Viagem não encontrada');
            }
            
            // Processar trajeto atual
            $trajeto = $viagem['trajeto'] ? json_decode($viagem['trajeto'], true) : [];
            if (!is_array($trajeto)) $trajeto = [];
            
            // Calcular distância desde último ponto
            $distanciaIncremento = 0;
            if (!empty($trajeto)) {
                $ultimoPonto = end($trajeto);
                $distanciaIncremento = haversine(
                    $ultimoPonto['latitude'], 
                    $ultimoPonto['longitude'], 
                    $latitude, 
                    $longitude
                );
            }
            
            // Criar novo ponto GPS
            $novoPonto = [
                'latitude' => floatval($latitude),
                'longitude' => floatval($longitude),
                'timestamp' => date('Y-m-d H:i:s'),
                'velocidade' => $velocidade ? floatval($velocidade) : null,
                'precisao' => $precisao ? floatval($precisao) : null,
                'distancia_incremento' => $distanciaIncremento
            ];
            
            // Adicionar ao trajeto
            $trajeto[] = $novoPonto;
            
            // 🔧 CORREÇÃO: Calcular distância total percorrida em METROS
            $distanciaTotalMetros = 0;
            for ($i = 1; $i < count($trajeto); $i++) {
                $distanciaTotalMetros += haversine(
                    $trajeto[$i-1]['latitude'], 
                    $trajeto[$i-1]['longitude'],
                    $trajeto[$i]['latitude'], 
                    $trajeto[$i]['longitude']
                );
            }
            
            // 🔧 CORREÇÃO: Converter metros para quilômetros para o banco
            $distanciaTotal = $distanciaTotalMetros / 1000;
            
            // Atualizar banco de dados
            $stmt = $this->pdo->prepare("
                UPDATE viagens 
                SET trajeto = ?, 
                    latitude_final = ?, 
                    longitude_final = ?,
                    distancia_gps = ?,
                    latitude_inicial = CASE 
                        WHEN latitude_inicial IS NULL OR latitude_inicial = 0 THEN ? 
                        ELSE latitude_inicial 
                    END,
                    longitude_inicial = CASE 
                        WHEN longitude_inicial IS NULL OR longitude_inicial = 0 THEN ? 
                        ELSE longitude_inicial 
                    END
                WHERE id = ?
            ");
            
            $stmt->execute([
                json_encode($trajeto),
                $latitude,
                $longitude,
                $distanciaTotal,
                $latitude, // latitude_inicial (se for primeiro ponto)
                $longitude, // longitude_inicial (se for primeiro ponto)
                $viagemId
            ]);
            
            // Preparar dados para resposta em tempo real
            $dadosRealtime = [
                'viagem_id' => $viagemId,
                'latitude' => $latitude,
                'longitude' => $longitude,
                'velocidade' => $velocidade,
                'distancia_total' => $distanciaTotal,
                'distancia_incremento' => $distanciaIncremento,
                'timestamp' => date('Y-m-d H:i:s'),
                'motorista_nome' => $viagem['motorista_nome'],
                'veiculo_info' => $viagem['veiculo_modelo'] . ' - ' . $viagem['veiculo_placa'],
                'trajeto' => $trajeto
            ];
            
            // Salvar dados para consulta em tempo real
            $this->trackingData[$viagemId] = $dadosRealtime;
            
            return $dadosRealtime;
            
        } catch (Exception $e) {
            error_log("Erro ao atualizar posição: " . $e->getMessage());
            throw $e;
        }
    }
    
    /**
     * Obtém dados de rastreamento em tempo real
     */
    public function obterDadosRealtime($viagemId) {
        // Primeiro, tentar obter do cache em memória
        if (isset($this->trackingData[$viagemId])) {
            return $this->trackingData[$viagemId];
        }
        
        // Se não estiver no cache, buscar do banco
        try {
            $stmt = $this->pdo->prepare("
                SELECT v.*, m.nome as motorista_nome, ve.modelo as veiculo_modelo, ve.placa as veiculo_placa
                FROM viagens v
                LEFT JOIN motoristas m ON v.tecnico_id = m.id
                LEFT JOIN veiculos ve ON v.veiculo_id = ve.id
                WHERE v.id = ?
            ");
            $stmt->execute([$viagemId]);
            $viagem = $stmt->fetch();
            
            if (!$viagem) {
                return null;
            }
            
            $trajeto = $viagem['trajeto'] ? json_decode($viagem['trajeto'], true) : [];
            if (!is_array($trajeto)) $trajeto = [];
            
            $ultimoPonto = !empty($trajeto) ? end($trajeto) : null;
            
            $dadosRealtime = [
                'viagem_id' => $viagemId,
                'latitude' => $ultimoPonto ? $ultimoPonto['latitude'] : $viagem['latitude_final'],
                'longitude' => $ultimoPonto ? $ultimoPonto['longitude'] : $viagem['longitude_final'],
                'velocidade' => $ultimoPonto ? $ultimoPonto['velocidade'] : null,
                'distancia_total' => $viagem['distancia_gps'] ?: 0,
                'timestamp' => $ultimoPonto ? $ultimoPonto['timestamp'] : date('Y-m-d H:i:s'),
                'motorista_nome' => $viagem['motorista_nome'],
                'veiculo_info' => $viagem['veiculo_modelo'] . ' - ' . $viagem['veiculo_placa'],
                'trajeto' => $trajeto
            ];
            
            // Salvar no cache
            $this->trackingData[$viagemId] = $dadosRealtime;
            
            return $dadosRealtime;
            
        } catch (Exception $e) {
            error_log("Erro ao obter dados realtime: " . $e->getMessage());
            return null;
        }
    }
    
    /**
     * Obtém todas as viagens ativas em tempo real
     */
    public function obterViagensAtivas() {
        try {
            $stmt = $this->pdo->prepare("
                SELECT v.id, v.tecnico_id, v.veiculo_id, v.cliente, v.motivo,
                       v.latitude_final, v.longitude_final, v.distancia_gps,
                       m.nome as motorista_nome, ve.modelo as veiculo_modelo, ve.placa as veiculo_placa,
                       v.data_inicio, v.data_fim
                FROM viagens v
                LEFT JOIN motoristas m ON v.tecnico_id = m.id
                LEFT JOIN veiculos ve ON v.veiculo_id = ve.id
                WHERE v.data_fim IS NULL
                ORDER BY v.data_inicio DESC
            ");
            $stmt->execute();
            $viagens = $stmt->fetchAll();
            
            $viagensAtivas = [];
            foreach ($viagens as $viagem) {
                $dadosRealtime = $this->obterDadosRealtime($viagem['id']);
                if ($dadosRealtime) {
                    $viagensAtivas[] = $dadosRealtime;
                }
            }
            
            return $viagensAtivas;
            
        } catch (Exception $e) {
            error_log("Erro ao obter viagens ativas: " . $e->getMessage());
            return [];
        }
    }
}

try {
    $pdo = conectarBanco();
    $tracker = new RealtimeTracker($pdo);
    
    $metodo = $_SERVER['REQUEST_METHOD'];
    $acao = $_GET['acao'] ?? 'status';
    
    switch ($acao) {
        case 'atualizar-posicao':
            if ($metodo === 'POST') {
                $input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
                
                if (!$input || !isset($input['viagem_id']) || !isset($input['latitude']) || !isset($input['longitude'])) {
                    resposta(false, null, 'viagem_id, latitude e longitude são obrigatórios', 400);
                }
                
                $dados = $tracker->atualizarPosicao(
                    $input['viagem_id'],
                    $input['latitude'],
                    $input['longitude'],
                    $input['velocidade'] ?? null,
                    $input['precisao'] ?? null
                );
                
                resposta(true, $dados, 'Posição atualizada em tempo real');
            } else {
                resposta(false, null, 'Método não suportado', 405);
            }
            break;
            
        case 'dados-realtime':
            if ($metodo === 'GET') {
                $viagemId = $_GET['viagem_id'] ?? null;
                
                if ($viagemId) {
                    $dados = $tracker->obterDadosRealtime($viagemId);
                    if ($dados) {
                        resposta(true, $dados, 'Dados em tempo real obtidos');
                    } else {
                        resposta(false, null, 'Viagem não encontrada', 404);
                    }
                } else {
                    $viagensAtivas = $tracker->obterViagensAtivas();
                    resposta(true, $viagensAtivas, 'Viagens ativas obtidas');
                }
            } else {
                resposta(false, null, 'Método não suportado', 405);
            }
            break;
            
        case 'obter-km-real-rota':
            if ($metodo === 'POST') {
                $input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
                
                if (!$input || !isset($input['rota_id'])) {
                    resposta(false, null, 'rota_id é obrigatório', 400);
                }
                
                try {
                    $stmt = $pdo->prepare("
                        SELECT 
                            sr.id,
                            sr.km_estimado,
                            sr.diferenca_km_calculada,
                            -- Calcular KM real das viagens da rota
                            (SELECT SUM(v.distancia_gps) 
                             FROM viagens v 
                             INNER JOIN rota_viagens rv ON v.id = rv.viagem_id 
                             WHERE rv.solicitacao_rota_id = sr.id 
                             AND v.distancia_gps > 0) as km_real_gps,
                            -- Calcular KM real usando odômetros
                            (SELECT SUM(COALESCE(v.odometro_final, 0) - COALESCE(v.odometro_inicial, 0))
                             FROM viagens v 
                             INNER JOIN rota_viagens rv ON v.id = rv.viagem_id 
                             WHERE rv.solicitacao_rota_id = sr.id 
                             AND v.odometro_final IS NOT NULL 
                             AND v.odometro_inicial IS NOT NULL) as km_real_odometro
                        FROM solicitacoes_rotas sr
                        WHERE sr.id = ?
                    ");
                    $stmt->execute([$input['rota_id']]);
                    $rota = $stmt->fetch();
                    
                    if (!$rota) {
                        resposta(false, null, 'Rota não encontrada', 404);
                    }
                    
                    // Usar KM GPS se disponível, senão usar odômetro
                    $kmReal = $rota['km_real_gps'] ?: $rota['km_real_odometro'] ?: 0;
                    
                    resposta(true, [
                        'rota_id' => $rota['id'],
                        'km_real' => $kmReal,
                        'km_estimado' => $rota['km_estimado'],
                        'km_real_gps' => $rota['km_real_gps'],
                        'km_real_odometro' => $rota['km_real_odometro']
                    ], 'KM real da rota obtido com sucesso');
                    
                } catch (Exception $e) {
                    error_log("Erro ao obter KM real da rota: " . $e->getMessage());
                    resposta(false, null, 'Erro interno: ' . $e->getMessage(), 500);
                }
            } else {
                resposta(false, null, 'Método não suportado', 405);
            }
            break;
            
        case 'status':
            resposta(true, [
                'status' => 'online',
                'timestamp' => date('Y-m-d H:i:s'),
                'servico' => 'Realtime Tracking'
            ], 'Serviço de rastreamento em tempo real ativo');
            break;
            
        default:
            resposta(false, null, 'Ação não encontrada', 404);
    }
    
} catch (Exception $e) {
    error_log("Erro no realtime-tracking.php: " . $e->getMessage());
    resposta(false, null, 'Erro interno: ' . $e->getMessage(), 500);
}
?>
