import math
from urllib.parse import quote_plus

from django.contrib import messages
from django.db import transaction
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse

from .forms import PropertyFlagForm, PropertyLocationForm, PropertyPhotoForm, PropertySuggestionForm
from .image_tools import compress_image, ocr_text_best_effort
from .models import PropertyEntry


def build_idealista_url(entry):
    query = entry.address or " ".join(filter(None, [entry.phone, entry.email]))
    if not query:
        return ""
    return f"https://www.idealista.com/en/search/{quote_plus(query)}/"


def _distance_km(lat1, lng1, lat2, lng2):
    if None in (lat1, lng1, lat2, lng2):
        return None
    radius = 6371
    phi1, phi2 = math.radians(float(lat1)), math.radians(float(lat2))
    d_phi = math.radians(float(lat2) - float(lat1))
    d_lambda = math.radians(float(lng2) - float(lng1))
    a = math.sin(d_phi / 2) ** 2 + math.cos(phi1) * math.cos(phi2) * math.sin(d_lambda / 2) ** 2
    return radius * (2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)))


def _decorate_distances(entries, user_lat, user_lng):
    decorated = []
    for entry in entries:
        distance = _distance_km(user_lat, user_lng, entry.latitude, entry.longitude) if user_lat and user_lng else None
        entry.distance_km = distance
        decorated.append(entry)
    return decorated


def home(request):
    entries = list(PropertyEntry.objects.filter(is_flagged=False).order_by("-created_at")[:6])
    context = {
        "page_title": "NearbyNest — mobile property pinboard",
        "meta_description": "A mobile-first PWA for posting nearby property sightings by current location or photo.",
        "recent_entries": entries,
        "total_entries": PropertyEntry.objects.count(),
        "photo_entries": PropertyEntry.objects.exclude(photo="").count(),
    }
    return render(request, "core/index.html", context)


def onboarding(request):
    context = {
        "page_title": "Onboarding permissions — NearbyNest",
        "meta_description": "Grant location, notification, and photo permissions for the mobile property pinboard.",
    }
    return render(request, "core/onboarding.html", context)


def property_list(request):
    sort = request.GET.get("sort", "recent")
    user_lat = request.GET.get("lat")
    user_lng = request.GET.get("lng")
    entries = list(PropertyEntry.objects.filter(is_flagged=False).order_by("-created_at"))
    entries = _decorate_distances(entries, user_lat, user_lng)
    if sort == "distance" and user_lat and user_lng:
        entries.sort(key=lambda entry: entry.distance_km if entry.distance_km is not None else float("inf"))
    context = {
        "page_title": "Public property list — NearbyNest",
        "meta_description": "Browse public property posts by recency or distance from your current location.",
        "entries": entries,
        "sort": sort,
        "user_lat": user_lat or "",
        "user_lng": user_lng or "",
    }
    return render(request, "core/property_list.html", context)


def property_detail(request, pk):
    entry = get_object_or_404(PropertyEntry.objects.prefetch_related("suggestions", "flags"), pk=pk)
    context = {
        "page_title": f"Property #{entry.pk} — NearbyNest",
        "meta_description": "Review a public property pin, extracted details, community suggestions, and flagging options.",
        "entry": entry,
        "suggestion_form": PropertySuggestionForm(),
        "flag_form": PropertyFlagForm(),
    }
    return render(request, "core/property_detail.html", context)


@transaction.atomic
def add_location_property(request):
    if request.method == "POST":
        form = PropertyLocationForm(request.POST)
        if form.is_valid():
            entry = form.save(commit=False)
            entry.source = PropertyEntry.Source.CURRENT_LOCATION
            entry.idealista_url = build_idealista_url(entry)
            entry.save()
            messages.success(request, "Property pinned to the public list.")
            return redirect(entry.get_absolute_url())
    else:
        form = PropertyLocationForm()
    context = {
        "page_title": "Add property by location or address — NearbyNest",
        "meta_description": "Add a property sighting from current GPS location or a typed/pasted address, with optional contact details.",
        "form": form,
    }
    return render(request, "core/property_form_location.html", context)


@transaction.atomic
def add_photo_property(request):
    if request.method == "POST":
        form = PropertyPhotoForm(request.POST, request.FILES)
        if form.is_valid():
            uploaded = form.cleaned_data["photo"]
            processed, error = compress_image(uploaded, uploaded.name)
            if error:
                form.add_error("photo", error)
            else:
                uploaded.seek(0)
                entry = form.save(commit=False)
                entry.source = PropertyEntry.Source.PHOTO
                entry.photo = processed["file"]
                if processed["latitude"] is not None and not entry.latitude:
                    entry.latitude = processed["latitude"]
                    entry.longitude = processed["longitude"]
                    entry.has_gps_data = True
                entry.extracted_text = ocr_text_best_effort(uploaded)
                entry.idealista_url = build_idealista_url(entry)
                entry.save()
                messages.success(request, "Photo compressed under 256KB and added to the pinboard.")
                return redirect(entry.get_absolute_url())
    else:
        form = PropertyPhotoForm()
    context = {
        "page_title": "Add property photo — NearbyNest",
        "meta_description": "Upload a property photo; the MVP compresses it, checks EXIF GPS, and attempts local OCR.",
        "form": form,
    }
    return render(request, "core/property_form_photo.html", context)


@transaction.atomic
def suggest_property_update(request, pk):
    entry = get_object_or_404(PropertyEntry, pk=pk)
    if request.method != "POST":
        return redirect(entry.get_absolute_url())
    form = PropertySuggestionForm(request.POST)
    if form.is_valid():
        suggestion = form.save(commit=False)
        suggestion.property_entry = entry
        suggestion.save()
        messages.success(request, "Thanks — your suggested details were saved for review.")
    else:
        messages.error(request, "Please add at least one valid detail before submitting a suggestion.")
    return redirect(entry.get_absolute_url())


@transaction.atomic
def flag_property(request, pk):
    entry = get_object_or_404(PropertyEntry, pk=pk)
    if request.method != "POST":
        return redirect(entry.get_absolute_url())
    form = PropertyFlagForm(request.POST)
    if form.is_valid():
        flag = form.save(commit=False)
        flag.property_entry = entry
        flag.save()
        entry.flag_count = entry.flags.count()
        entry.is_flagged = entry.flag_count >= 3
        entry.save(update_fields=["flag_count", "is_flagged", "updated_at"])
        messages.success(request, "Flag saved. Entries with repeated flags are hidden from the public list.")
    else:
        messages.error(request, "Add a short reason so reviewers know what to check.")
    return redirect(entry.get_absolute_url())
