import requests
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_GET, require_POST
import json

from .models import NominationPlace
from .utils import save_nomination_place, serialize_place


# @require_GET
# def reverse_geocode(request):
#     lat = request.GET.get('lat')
#     lon = request.GET.get('lon')

#     if not lat or not lon:
#         return JsonResponse({'error': 'Missing coordinates'}, status=400)

#     try:
#         lat_f = float(lat)
#         lon_f = float(lon)
#     except ValueError:
#         return JsonResponse({'error': 'Invalid coordinates'}, status=400)

#     # Try local match
#     for place in NominationPlace.objects.exclude(boundingbox=None):
#         try:
#             bbox = list(map(float, place.boundingbox))
#             if bbox[0] <= lat_f <= bbox[1] and bbox[2] <= lon_f <= bbox[3]:
#                 print("✅ Match found via bounding box")
#                 return JsonResponse(serialize_place(place))
#         except Exception:
#             continue

#     # Try nearby range
#     nearby = NominationPlace.objects.filter(
#         lat__gte=lat_f - 0.01, lat__lte=lat_f + 0.01,
#         lon__gte=lon_f - 0.01, lon__lte=lon_f + 0.01
#     )
#     if nearby.exists():
#         return JsonResponse(serialize_place(nearby.first()))

#     # Fallback to Nominatim
#     try:
#         res = requests.get(
#             "https://nominatim.openstreetmap.org/reverse",
#             params={'format': 'jsonv2', 'lat': lat, 'lon': lon},
#             headers={'User-Agent': 'ViralPe/1.0 (contact@viralpe.com)'},
#             timeout=5
#         )
#         res.raise_for_status()
#         data = res.json()
#         place = save_nomination_place(data)
#         return JsonResponse(serialize_place(place))
#     except Exception as e:
#         return JsonResponse({'error': 'Nominatim failed', 'details': str(e)}, status=500)

@require_GET
def reverse_geocode(request):
    lat = request.GET.get('lat')
    lon = request.GET.get('lon')
    if not lat or not lon:
        return JsonResponse({'error': 'Missing lat or lon parameters'}, status=400)
    
    try:
        lat_f = float(lat)
        lon_f = float(lon)
    except ValueError:
        return JsonResponse({'error': 'Invalid lat or lon'}, status=400)

    # First try boundingbox matching
    for place in NominationPlace.objects.exclude(boundingbox=None):
        try:
            bbox = list(map(float, place.boundingbox))
            lat_min, lat_max, lon_min, lon_max = bbox
            if lat_min <= lat_f <= lat_max and lon_min <= lon_f <= lon_max:
                print("✅ Match found via bounding box")
                return JsonResponse(serialize_place(place))
        except Exception as e:
            continue  # In case of bad bounding box

    # Fallback to basic range check
    nearby_places = NominationPlace.objects.filter(
        lat__gte=lat_f - 0.01, lat__lte=lat_f + 0.01,
        lon__gte=lon_f - 0.01, lon__lte=lon_f + 0.01
    )

    if nearby_places.exists():
        print("✅ Match found via coordinate range filter")
        place = nearby_places.first()
        return JsonResponse(serialize_place(place))

    # Fallback to external API
    print("🌐 Fetching location data from Nominatim external API.")
    nominatim_url = "https://nominatim.openstreetmap.org/reverse"
    params = {
        'format': 'jsonv2',
        'lat': lat,
        'lon': lon,
    }
    headers = {
        'User-Agent': 'MyDjangoApp/1.0 (contact@satfarm.com)'
    }
    try:
        response = requests.get(nominatim_url, params=params, headers=headers, timeout=5)
        response.raise_for_status()
        nominatim_data = response.json()
    except requests.RequestException as e:
        return JsonResponse({'error': 'Failed to fetch data from Nominatim', 'details': str(e)}, status=500)

    place = save_nomination_place(nominatim_data)
    if not place:
        return JsonResponse({'error': 'Failed to save place data'}, status=500)

    return JsonResponse(serialize_place(place))

@csrf_exempt
@require_POST
def save_pincode(request):
    try:
        data = json.loads(request.body)
        pincode = data.get("pincode")
        if not pincode or len(pincode) != 6:
            return JsonResponse({"error": "Invalid PIN"}, status=400)
        request.session["user_pincode"] = pincode
        return JsonResponse({"message": "PIN saved", "pincode": pincode})
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)

# geoapi/views.py

from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_GET
from django.http import JsonResponse
from .models import NominationPlace, PincodeUsageLog
from .utils import is_valid_api_request
from .utils import save_nomination_place, serialize_place
import requests

@require_GET
@csrf_exempt
def api_reverse_geocode(request):
    lat = request.GET.get('lat')
    lon = request.GET.get('lon')
    client_id = request.GET.get('client_id') or request.headers.get('X-Client-ID')
    api_key = request.GET.get('api_key') or request.headers.get('X-API-Key')

    if not is_valid_api_request(client_id, api_key):
        return JsonResponse({'error': 'Unauthorized'}, status=403)

    if not lat or not lon:
        return JsonResponse({'error': 'Missing lat or lon parameters'}, status=400)

    try:
        lat_f = float(lat)
        lon_f = float(lon)
    except ValueError:
        return JsonResponse({'error': 'Invalid coordinates'}, status=400)

    # 1. Bounding Box
    for place in NominationPlace.objects.exclude(boundingbox=None):
        try:
            bbox = list(map(float, place.boundingbox))
            if bbox[0] <= lat_f <= bbox[1] and bbox[2] <= lon_f <= bbox[3]:
                _log_pincode(client_id, place.postcode)
                return JsonResponse(serialize_place(place))
        except:
            continue

    # 2. Nearby filter
    nearby = NominationPlace.objects.filter(
        lat__gte=lat_f - 0.01, lat__lte=lat_f + 0.01,
        lon__gte=lon_f - 0.01, lon__lte=lon_f + 0.01
    ).first()

    if nearby:
        _log_pincode(client_id, nearby.postcode)
        return JsonResponse(serialize_place(nearby))

    # 3. External API
    try:
        response = requests.get(
            "https://nominatim.openstreetmap.org/reverse",
            params={'format': 'jsonv2', 'lat': lat, 'lon': lon},
            headers={'User-Agent': 'ViralPeGeoAPI/1.0 (contact@viralpe.com)'},
            timeout=5
        )
        response.raise_for_status()
        data = response.json()
        place = save_nomination_place(data)
        if place:
            _log_pincode(client_id, place.postcode)
            return JsonResponse(serialize_place(place))
        return JsonResponse({'error': 'Failed to save place'}, status=500)
    except Exception as e:
        return JsonResponse({'error': 'External API error', 'details': str(e)}, status=500)

def _log_pincode(client_id, pincode):
    if pincode and len(pincode) == 6:
        PincodeUsageLog.objects.create(client_id=client_id, pincode=pincode)
