"""JM3 Verification Engine.

Verification is now universal — it scores any Asset that carries photo + GPS
evidence, not just trees. Every registered asset is scored:

    verified   - has photo evidence and passes all fraud checks
    pending    - missing photo evidence; cannot yet be trusted
    suspicious - failed a fraud check (reused photo, duplicate location)

Checks implemented:
  1. Reused photo   - same image submitted for more than one asset
  2. Duplicate      - another asset already registered within ~5 metres
"""

import hashlib
import math

DUPLICATE_RADIUS_METRES = 5.0


def hash_image(file_field):
    if not file_field:
        return ""
    try:
        file_field.open("rb")
        digest = hashlib.sha256()
        for chunk in file_field.chunks():
            digest.update(chunk)
        return digest.hexdigest()
    except Exception:
        return ""
    finally:
        try:
            file_field.close()
        except Exception:
            pass


def _haversine_metres(lat1, lon1, lat2, lon2):
    r = 6371000.0
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dphi = math.radians(lat2 - lat1)
    dlam = math.radians(lon2 - lon1)
    a = math.sin(dphi / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dlam / 2) ** 2
    return 2 * r * math.asin(math.sqrt(a))


def verify_asset(asset):
    """Score a freshly saved asset. Sets verification fields and persists them."""
    from .models import Asset

    reasons = []

    if asset.photo:
        asset.photo_hash = hash_image(asset.photo)
        if asset.photo_hash:
            clash = Asset.objects.filter(photo_hash=asset.photo_hash).exclude(pk=asset.pk).first()
            if clash:
                reasons.append(f"Photo reused from {clash.tag_code}")

    delta = 0.0001
    nearby = (
        Asset.objects.filter(
            asset_type=asset.asset_type,
            latitude__range=(asset.latitude - delta, asset.latitude + delta),
            longitude__range=(asset.longitude - delta, asset.longitude + delta),
        )
        .exclude(pk=asset.pk)
    )
    for other in nearby:
        if _haversine_metres(asset.latitude, asset.longitude, other.latitude, other.longitude) <= DUPLICATE_RADIUS_METRES:
            reasons.append(f"Possible duplicate of {other.tag_code}")
            break

    if reasons:
        status = "suspicious"
    elif asset.photo and asset.photo_hash:
        status = "verified"
    else:
        status = "pending"

    asset.verification_status = status
    asset.verification_notes = "; ".join(reasons)[:300]
    asset.save(update_fields=["verification_status", "verification_notes", "photo_hash"])
    return status, asset.verification_notes
