<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;

use App\Services\PricingService;

class MapController extends Controller
{
    protected $pricingService;

    public function __construct(PricingService $pricingService)
    {
        $this->pricingService = $pricingService;
    }

    /**
     * Get route between two coordinates using OSRM.
     */
    public function getRoute(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'start_lat' => 'required|numeric',
            'start_lng' => 'required|numeric',
            'end_lat' => 'required|numeric',
            'end_lng' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $start = "{$request->start_lng},{$request->start_lat}";
        $end = "{$request->end_lng},{$request->end_lat}";

        $cacheKey = "route_" . md5("{$start}_{$end}");

        return Cache::remember($cacheKey, 3600, function () use ($start, $end, $request) {
            $url = "https://router.project-osrm.org/route/v1/driving/{$start};{$end}?overview=full&geometries=geojson";

            try {
                $response = Http::get($url);
                if ($response->successful()) {
                    $osmData = $response->json();
                    
                    $distance = $osmData['routes'][0]['distance']; // meters
                    $duration = $osmData['routes'][0]['duration']; // seconds

                    $categories = ['metrolite', 'metroride', 'metropremium'];
                    $estimates = [];

                    foreach ($categories as $cat) {
                        $fareDetails = $this->pricingService->calculateFare(
                            $distance, 
                            $duration, 
                            $request->start_lat, 
                            $request->start_lng,
                            $cat
                        );
                        $estimates[$cat] = $fareDetails;
                    }

                    return [
                        'success' => true,
                        'route' => $osmData,
                        'distance' => $distance,
                        'duration' => $duration,
                        'estimates' => $estimates,
                        'estimated_fare' => $estimates['metroride']['final_fare'], // backward compatibility
                    ];
                }
                return ['success' => false, 'message' => 'Failed to fetch route from OSRM'];
            } catch (\Exception $e) {
                return ['success' => false, 'message' => 'OSRM service error: ' . $e->getMessage()];
            }
        });
    }

    /**
     * Geocode an address query using Nominatim.
     */
    public function geocode(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'q' => 'required|string',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $query = $request->input('q');

        try {
            $response = Http::withHeaders([
                'User-Agent' => 'HwebRideApp/1.0'
            ])->get("https://nominatim.openstreetmap.org/search", [
                'q' => $query,
                'format' => 'json'
            ]);

            if ($response->successful()) {
                return response()->json([
                    'success' => true,
                    'results' => $response->json()
                ]);
            }
            return response()->json(['success' => false, 'message' => 'Failed to geocode address'], 400);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Nominatim geocoding error: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Reverse geocode coordinates using Nominatim.
     */
    public function reverseGeocode(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'lat' => 'required|numeric',
            'lng' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $lat = $request->lat;
        $lng = $request->lng;

        try {
            $response = Http::withHeaders([
                'User-Agent' => 'HwebRideApp/1.0'
            ])->get("https://nominatim.openstreetmap.org/reverse", [
                'lat' => $lat,
                'lon' => $lng,
                'format' => 'json'
            ]);

            if ($response->successful()) {
                return response()->json([
                    'success' => true,
                    'result' => $response->json()
                ]);
            }
            return response()->json(['success' => false, 'message' => 'Failed to reverse geocode coordinates'], 400);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Nominatim reverse geocoding error: ' . $e->getMessage()], 500);
        }
    }
}
