<?php

namespace App\Http\Controllers\Api\Driver;

use App\Events\DriverLocationUpdated;
use App\Http\Controllers\Controller;
use App\Models\DriverShift;
use App\Services\ShiftService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class ShiftController extends Controller
{
    private const EARTH_RADIUS_METERS = 6371000;

    /**
     * POST /api/driver/shifts/start
     */
    public function start(Request $request, ShiftService $shifts): JsonResponse
    {
        $driver = $request->user()->driver;
        abort_unless($driver, 404, __('api.no_driver_profile'));

        $data = $request->validate([
            'vehicle_id' => ['required', 'exists:vehicles,id'],
            'lat' => ['required', 'numeric'],
            'lng' => ['required', 'numeric'],
        ]);

        if ($reason = $shifts->blockingReason($driver, $data['vehicle_id'])) {
            return response()->json(['message' => $reason], 409);
        }

        $shift = DriverShift::create([
            'driver_id' => $driver->id,
            'vehicle_id' => $data['vehicle_id'],
            'started_at' => now(),
            'start_lat' => $data['lat'],
            'start_lng' => $data['lng'],
            'last_lat' => $data['lat'],
            'last_lng' => $data['lng'],
            'is_available' => true,
        ]);

        return response()->json(['shift' => $shift], 201);
    }

    /**
     * POST /api/driver/shifts/end
     */
    public function end(Request $request, ShiftService $shifts): JsonResponse
    {
        $driver = $request->user()->driver;
        abort_unless($driver, 404, __('api.no_driver_profile'));

        $shift = DriverShift::where('driver_id', $driver->id)->whereNull('ended_at')->first();
        abort_unless($shift, 409, __('api.no_active_shift_to_end'));

        $shifts->end($shift, $request->user());

        return response()->json(['message' => __('api.shift_ended'), 'shift' => $shift->fresh()]);
    }

    /**
     * GET /api/driver/shifts/active
     */
    public function active(Request $request): JsonResponse
    {
        $driver = $request->user()->driver;
        abort_unless($driver, 404, __('api.no_driver_profile'));

        $shift = DriverShift::with('vehicle')->where('driver_id', $driver->id)->whereNull('ended_at')->first();
        abort_unless($shift, 409, __('api.no_active_shift'));

        return response()->json(['shift' => $shift]);
    }

    /**
     * GET /api/driver/shifts/history
     */
    public function history(Request $request): JsonResponse
    {
        $driver = $request->user()->driver;
        abort_unless($driver, 404, __('api.no_driver_profile'));

        $shifts = DriverShift::with('vehicle')
            ->where('driver_id', $driver->id)
            ->latest('started_at')
            ->paginate(20);

        return response()->json($shifts);
    }

    /**
     * POST /api/driver/shifts/location — live GPS ping while on shift.
     * Server-computes speed from consecutive pings (matches the old
     * project's approach) and broadcasts it for the admin's live map.
     */
    public function updateLocation(Request $request): JsonResponse
    {
        $driver = $request->user()->driver;
        abort_unless($driver, 404, __('api.no_driver_profile'));

        $data = $request->validate([
            'lat' => ['required', 'numeric'],
            'lng' => ['required', 'numeric'],
        ]);

        $shift = DriverShift::where('driver_id', $driver->id)->whereNull('ended_at')->first();
        abort_unless($shift, 409, __('api.no_active_shift'));

        $speed = 0.0;

        if ($shift->last_lat && $shift->last_lng && $shift->updated_at) {
            $elapsedSeconds = max(1, now()->diffInSeconds($shift->updated_at));
            $distanceMeters = $this->haversineMeters(
                (float) $shift->last_lat, (float) $shift->last_lng,
                $data['lat'], $data['lng']
            );
            $speed = $distanceMeters < 1 ? 0.0 : round($distanceMeters / $elapsedSeconds, 2);
        }

        $shift->update([
            'last_lat' => $data['lat'],
            'last_lng' => $data['lng'],
            'speed' => $speed,
        ]);

        broadcast(new DriverLocationUpdated($driver->id, $data['lat'], $data['lng'], $speed))->toOthers();

        return response()->json(['speed' => $speed]);
    }

    private function haversineMeters(float $lat1, float $lng1, float $lat2, float $lng2): float
    {
        $latDelta = deg2rad($lat2 - $lat1);
        $lngDelta = deg2rad($lng2 - $lng1);

        $a = sin($latDelta / 2) ** 2
            + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($lngDelta / 2) ** 2;

        return self::EARTH_RADIUS_METERS * 2 * atan2(sqrt($a), sqrt(1 - $a));
    }
}
