"""Catalog of real delivery regions (Kinondoni, Dar es Salaam, Arusha, ...).
Self-improving from HERE's structured address data (see get_or_create_region
below and market/views.py::region_search) rather than admin-typed — same
"grows from real resolved locations" pattern as market/known_areas.py.
Markets, warehouses, industries, picker profiles, and the known-areas
gazetteer all optionally tag themselves with one of these (see
market/known_areas.py for how a delivery location's region gets resolved
from this)."""

from django.core.cache import cache

from accounts.supabase_client import get_client

_CACHE_KEY = 'pickker_regions_list'
_CACHE_TTL = 60


def _invalidate():
    cache.delete(_CACHE_KEY)


def get_all_regions():
    regions = cache.get(_CACHE_KEY)
    if regions is None:
        resp = get_client().table('pickker_regions').select('*').order('name_en').execute()
        regions = resp.data
        cache.set(_CACHE_KEY, regions, _CACHE_TTL)
    return regions


def get_region(region_id):
    if not region_id:
        return None
    resp = get_client().table('pickker_regions').select('*').eq('id', region_id).execute()
    return resp.data[0] if resp.data else None


def get_regions_by_id(region_ids):
    region_ids = [r for r in set(region_ids) if r]
    if not region_ids:
        return {}
    resp = get_client().table('pickker_regions').select('*').in_('id', region_ids).execute()
    return {r['id']: r for r in resp.data}


def create_region(name_en, name_sw=''):
    name_en = (name_en or '').strip()
    if not name_en:
        return
    existing = get_client().table('pickker_regions').select('id').ilike('name_en', name_en).execute()
    if existing.data:
        return
    get_client().table('pickker_regions').insert({
        'name_en': name_en, 'name_sw': (name_sw or '').strip(),
    }).execute()
    _invalidate()


def get_or_create_region(name_en, name_sw=''):
    """Find a region by name (case-insensitive), or create it on first
    sight. Every region-picking form in the app now resolves a region this
    way — via market.views::region_search, backed by HERE's structured
    address data — rather than an admin free-typing a name into existence
    (create_region() above is unchanged and still used by the admin
    rename/edit form, just no longer the only way a region comes to
    exist). Returns the full region row, or None for an empty name."""
    name_en = (name_en or '').strip()
    if not name_en:
        return None
    client = get_client()
    existing = client.table('pickker_regions').select('*').ilike('name_en', name_en).execute()
    if existing.data:
        return existing.data[0]
    resp = client.table('pickker_regions').insert({
        'name_en': name_en, 'name_sw': (name_sw or '').strip(),
    }).execute()
    _invalidate()
    return resp.data[0] if resp.data else None


def update_region(region_id, name_en, name_sw=''):
    name_en = (name_en or '').strip()
    if not name_en:
        return
    get_client().table('pickker_regions').update({
        'name_en': name_en, 'name_sw': (name_sw or '').strip(),
    }).eq('id', region_id).execute()
    _invalidate()


def delete_region(region_id):
    get_client().table('pickker_regions').delete().eq('id', region_id).execute()
    _invalidate()


def localize_region(region, lang):
    if not region:
        return None
    return (region.get('name_sw') or region['name_en']) if lang == 'sw' else region['name_en']


def resolve_region_for_location(lat, lng):
    """Which registered region a lat/lng falls in, via the nearest
    region-tagged known area (see market/known_areas.py) — a fast local
    lookup rather than a live reverse-geocode call on every checkout, so a
    flaky external API can never block an order. Returns None (never
    raises) if no region-tagged area is close enough to guess from — callers
    treat that as "unknown region," which fails open (doesn't block the
    order) rather than fail closed."""
    from .geo import haversine_km
    from .known_areas import get_all_areas

    if lat is None or lng is None:
        return None

    candidates = [
        a for a in get_all_areas()
        if a.get('region_id') and a.get('lat') is not None and a.get('lng') is not None
    ]
    if not candidates:
        return None

    nearest = min(candidates, key=lambda a: haversine_km(lat, lng, float(a['lat']), float(a['lng'])))
    return nearest['region_id']
