<?php

namespace App\Services;

use App\Models\Ride;
use App\Models\RouteDeviation;
use App\Models\SOSAlert;
use App\Models\EmergencyContact;
use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class GodsEyeService
{
    protected float $deviationThreshold;
    protected int $responseTimeout;
    protected int $checkInterval;

    public function __construct()
    {
        $this->deviationThreshold = config('app.gods_eye_deviation_threshold', 100); // meters
        $this->responseTimeout = config('app.gods_eye_response_timeout', 30); // seconds
        $this->checkInterval = config('app.gods_eye_check_interval', 5); // seconds
    }

    /**
     * Check if driver has deviated from expected route
     */
    public function checkDeviation(Ride $ride, float $currentLat, float $currentLng): ?RouteDeviation
    {
        if (empty($ride->route_polyline) || $ride->status !== 'started') {
            return null;
        }

        $expectedLatLng = $this->getExpectedPosition($ride);
        if (!$expectedLatLng) {
            return null;
        }

        $deviationDistance = $this->calculateDistance(
            $expectedLatLng['lat'], $expectedLatLng['lng'],
            $currentLat, $currentLng
        );

        if ($deviationDistance > $this->deviationThreshold) {
            return $this->recordDeviation($ride, $expectedLatLng, $currentLat, $currentLng, $deviationDistance);
        }

        return null;
    }

    /**
     * Get expected position based on route polyline and progress
     */
    protected function getExpectedPosition(Ride $ride): ?array
    {
        $polyline = $ride->route_polyline;
        if (empty($polyline)) return null;

        $progress = $this->calculateRideProgress($ride);
        $index = min(
            (int)($progress * count($polyline)),
            count($polyline) - 1
        );

        return $polyline[$index] ?? null;
    }

    /**
     * Calculate how far along the ride is (0.0 to 1.0)
     */
    protected function calculateRideProgress(Ride $ride): float
    {
        if (!$ride->started_at) return 0;

        $totalDuration = ($ride->duration > 0) ? $ride->duration : 600; // default 10 min
        $elapsedSeconds = now()->diffInSeconds($ride->started_at);
        $elapsedMinutes = $elapsedSeconds / 60;

        return min($elapsedMinutes / $totalDuration, 0.95); // cap at 95%
    }

    /**
     * Record a route deviation and trigger alert flow
     */
    protected function recordDeviation(
        Ride $ride,
        array $expected,
        float $actualLat,
        float $actualLng,
        float $deviationMeters
    ): RouteDeviation {
        $deviation = RouteDeviation::create([
            'ride_id' => $ride->id,
            'user_id' => $ride->user_id,
            'driver_id' => $ride->driver_id,
            'expected_lat' => $expected['lat'],
            'expected_lng' => $expected['lng'],
            'actual_lat' => $actualLat,
            'actual_lng' => $actualLng,
            'deviation_distance_meters' => $deviationMeters,
            'status' => 'detected',
            'detected_at' => now(),
        ]);

        // Mark ride as having deviation
        $ride->update([
            'has_route_deviation' => true,
            'last_deviation_at' => now(),
        ]);

        // Send push notification to user
        $this->notifyUserOfDeviation($ride, $deviationMeters);

        // Schedule escalation if user doesn't respond
        $this->scheduleEscalation($deviation);

        Log::warning("God's Eye: Route deviation detected", [
            'ride_id' => $ride->id,
            'deviation_meters' => $deviationMeters,
        ]);

        return $deviation;
    }

    /**
     * Notify user via push notification about route deviation
     */
    protected function notifyUserOfDeviation(Ride $ride, float $deviationMeters): void
    {
        $user = $ride->user;
        if (!$user || !$user->fcm_token) return;

        try {
            // Firebase Cloud Message push
            $this->sendPushNotification(
                $user->fcm_token,
                '⚠️ Route Deviation Detected!',
                "Your driver is {$deviationMeters}m off the expected route. Tap to view."
            );
        } catch (\Exception $e) {
            Log::error("God's Eye: Failed to notify user: {$e->getMessage()}");
        }
    }

    /**
     * Schedule escalation - if user doesn't respond within timeout, escalate
     */
    protected function scheduleEscalation(RouteDeviation $deviation): void
    {
        // In production, dispatch a delayed job/event
        // dispatch(new CheckDeviationResponse($deviation->id))->delay(now()->addSeconds($this->responseTimeout));
        
        // For simplicity, we'll log and the admin panel checks periodically
        Log::info("God's Eye: Escalation scheduled for deviation {$deviation->id}", [
            'timeout' => $this->responseTimeout,
        ]);
    }

    /**
     * Acknowledge deviation - user confirmed they're safe
     */
    public function acknowledgeDeviation(string $deviationId): RouteDeviation
    {
        $deviation = RouteDeviation::findOrFail($deviationId);
        $deviation->update([
            'status' => 'user_acknowledged',
            'acknowledged_at' => now(),
        ]);

        // Reset ride deviation flag
        $ride = $deviation->ride;
        if ($ride) {
            $ride->update(['has_route_deviation' => false]);
        }

        Log::info("God's Eye: Deviation acknowledged by user", ['deviation_id' => $deviationId]);
        return $deviation;
    }

    /**
     * Escalate deviation - user didn't respond, alert admin and emergency services
     */
    public function escalateDeviation(string $deviationId): void
    {
        $deviation = RouteDeviation::findOrFail($deviationId);
        $deviation->update([
            'status' => 'escalated',
            'escalated_at' => now(),
        ]);

        $ride = $deviation->ride;
        $user = $ride?->user;

        // 1. Create SOS Alert
        $sosAlert = SOSAlert::create([
            'user_id' => $deviation->user_id,
            'ride_id' => $deviation->ride_id,
            'latitude' => $deviation->actual_lat,
            'longitude' => $deviation->actual_lng,
            'address' => $this->getAddressFromCoordinates($deviation->actual_lat, $deviation->actual_lng),
            'type' => 'route_deviation',
            'status' => 'active',
            'description' => "Emergency escalated: Driver deviated route by {$deviation->deviation_distance_meters}m and user did not respond.",
        ]);

        // 2. Notify emergency contacts
        $this->notifyEmergencyContacts($user, $sosAlert);

        // 3. Notify admin
        $this->notifyAdmin($sosAlert);

        // 4. Call emergency services (simulated - in production, integrate with Twilio)
        $this->callEmergencyServices($sosAlert);

        Log::critical("God's Eye: DEVIATION ESCALATED TO EMERGENCY", [
            'deviation_id' => $deviationId,
            'sos_alert_id' => $sosAlert->id,
        ]);
    }

    /**
     * Notify user's emergency contacts
     */
    protected function notifyEmergencyContacts(?User $user, SOSAlert $alert): void
    {
        if (!$user) return;

        $contacts = EmergencyContact::where('user_id', $user->id)
            ->where('notify_on_emergency', true)
            ->get();

        foreach ($contacts as $contact) {
            try {
                // Send SMS via Twilio or email
                Mail::raw(
                    "EMERGENCY: {$user->full_name} needs help!\n\n"
                    . "Location: {$alert->latitude}, {$alert->longitude}\n"
                    . "Alert Type: Route Deviation - No response from rider\n"
                    . "Please check on them immediately.\n\n"
                    . "- LynX Safety Team",
                    function ($message) use ($contact) {
                        $message->to($contact->phone . '@sms.gateway.com') // SMS gateway
                            ->subject('🚨 LynX Emergency Alert');
                    }
                );

                Log::info("God's Eye: Notified emergency contact {$contact->name}");
            } catch (\Exception $e) {
                Log::error("God's Eye: Failed to notify contact: {$e->getMessage()}");
            }
        }
    }

    /**
     * Notify admin team about the escalation
     */
    protected function notifyAdmin(SOSAlert $alert): void
    {
        $adminEmail = config('app.admin_email', 'admin@mylynx.cc');

        try {
            Mail::raw(
                "🚨 GOD'S EYE EMERGENCY ESCALATION\n\n"
                . "A route deviation has been escalated to emergency level.\n\n"
                . "Alert ID: {$alert->id}\n"
                . "User ID: {$alert->user_id}\n"
                . "Ride ID: {$alert->ride_id}\n"
                . "Location: {$alert->latitude}, {$alert->longitude}\n"
                . "Status: ACTIVE - Requires immediate attention\n\n"
                . "Please respond via the God's Eye Dashboard:\n"
                . config('app.url') . "/admin/gods-eye\n\n"
                . "- LynX Safety System",
                function ($message) use ($adminEmail) {
                    $message->to($adminEmail)
                        ->subject('🚨 GOD\'S EYE - Emergency Escalation');
                }
            );
        } catch (\Exception $e) {
            Log::error("God's Eye: Failed to notify admin: {$e->getMessage()}");
        }
    }

    /**
     * Simulate calling emergency services
     */
    protected function callEmergencyServices(SOSAlert $alert): void
    {
        $emergencyEmail = config('app.emergency_email', '911@mylynx.cc');

        try {
            Mail::raw(
                "EMERGENCY SERVICES CALL - AUTOMATED ALERT\n\n"
                . "This is an automated emergency alert from LynX.\n\n"
                . "A rider may be in danger. Details:\n"
                . "- Location: {$alert->latitude}, {$alert->longitude}\n"
                . "- Type: Route deviation with no rider response\n"
                . "- Address: {$alert->address}\n"
                . "- Alert Time: {$alert->created_at}\n\n"
                . "Please dispatch emergency services to the above location.\n\n"
                . "- LynX Safety System",
                function ($message) use ($emergencyEmail) {
                    $message->to($emergencyEmail)
                        ->subject('🚨 LYNX EMERGENCY - Immediate Dispatch Required');
                }
            );

            Log::info("God's Eye: Emergency services notified");
        } catch (\Exception $e) {
            Log::error("God's Eye: Failed to call emergency services: {$e->getMessage()}");
        }
    }

    /**
     * Send push notification via Firebase
     */
    protected function sendPushNotification(string $token, string $title, string $body): void
    {
        // Firebase Cloud Messaging integration
        $firebaseUrl = 'https://fcm.googleapis.com/fcm/send';
        $serverKey = config('services.firebase.server_key');

        try {
            Http::withHeaders([
                'Authorization' => "key={$serverKey}",
                'Content-Type' => 'application/json',
            ])->post($firebaseUrl, [
                'to' => $token,
                'notification' => [
                    'title' => $title,
                    'body' => $body,
                    'sound' => 'default',
                ],
                'data' => [
                    'type' => 'route_deviation',
                    'priority' => 'high',
                ],
            ]);
        } catch (\Exception $e) {
            Log::error("Push notification failed: {$e->getMessage()}");
        }
    }

    /**
     * Get address from coordinates using Google Maps Geocoding
     */
    protected function getAddressFromCoordinates(float $lat, float $lng): string
    {
        try {
            $response = Http::get('https://maps.googleapis.com/maps/api/geocode/json', [
                'latlng' => "{$lat},{$lng}",
                'key' => config('services.google.maps_api_key'),
            ]);

            $data = $response->json();
            if ($data['status'] === 'OK' && !empty($data['results'])) {
                return $data['results'][0]['formatted_address'];
            }
        } catch (\Exception $e) {
            Log::error("Geocoding failed: {$e->getMessage()}");
        }

        return "{$lat}, {$lng}";
    }

    /**
     * Calculate distance between two coordinates using Haversine formula
     */
    protected function calculateDistance(float $lat1, float $lng1, float $lat2, float $lng2): float
    {
        $earthRadius = 6371000; // meters
        $dLat = deg2rad($lat2 - $lat1);
        $dLng = deg2rad($lng2 - $lng1);
        $a = sin($dLat / 2) * sin($dLat / 2) +
             cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
             sin($dLng / 2) * sin($dLng / 2);
        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
        return $earthRadius * $c;
    }

    /**
     * Get active deviations for admin dashboard
     */
    public function getActiveDeviations()
    {
        return RouteDeviation::whereIn('status', ['detected', 'escalated'])
            ->with(['ride', 'user', 'driver'])
            ->orderBy('detected_at', 'desc')
            ->get();
    }

    /**
     * Get active SOS alerts for admin dashboard
     */
    public function getActiveAlerts()
    {
        return SOSAlert::where('status', 'active')
            ->with(['user', 'ride'])
            ->orderBy('created_at', 'desc')
            ->get();
    }
}
