import { BaseEngine, IMetadataProvider, UserInfo } from "@memberjunction/core";
import { MJCountryEntity, MJStateProvinceEntity } from "../generated/entity_subclasses.js";
/**
 * Result of a point-in-polygon resolution.
 */
export interface GeoPointResolution {
    /** The matched country, if any */
    Country: MJCountryEntity | undefined;
    /** The matched state/province, if any */
    State: MJStateProvinceEntity | undefined;
}
/**
 * GeoDataEngine provides cached, in-memory access to Country and StateProvince
 * reference data, plus point-in-polygon resolution against country/state boundaries.
 * All lookups are O(1) via pre-built Maps keyed by common lookup patterns.
 *
 * **Loaded on demand**, not at app startup. The dataset is large (~3,000+ rows
 * with BoundaryGeoJSON blobs) and parsing the geometry takes ~3–4s synchronously,
 * so we only pay that cost when geocoding or geo lookups are actually needed.
 *
 * **Caller contract**: `await GeoDataEngine.Instance.Config(...)` once before
 * calling any sync lookup method. `Config()` is idempotent — concurrent calls
 * dedup against a single in-flight load (see `BaseEngine.Load`), and repeated
 * calls after load complete return immediately. If no entity in the tenant has
 * `SupportsGeoCoding=1`, `Config()` returns early and lookups will return
 * `undefined` — callers already handle the not-found case so the empty state
 * is safe to leave in place.
 *
 * Usage:
 * ```typescript
 * await GeoDataEngine.Instance.Config(false, contextUser);
 * const country = GeoDataEngine.Instance.GetCountryByISO2('US');
 * const state = GeoDataEngine.Instance.GetStateByCode(country.ID, 'CO');
 * ```
 */
export declare class GeoDataEngine extends BaseEngine<GeoDataEngine> {
    static get Instance(): GeoDataEngine;
    private _countries;
    private _stateProvinces;
    private _countriesByISO2;
    private _countriesByISO3;
    private _countriesByName;
    private _countriesById;
    private _statesByCountryAndCode;
    private _statesByCountryAndName;
    private _statesById;
    private _countryGeometries;
    private _stateGeometries;
    /** Maps countryId → array of state geometries for that country */
    private _stateGeometriesByCountry;
    Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<void>;
    protected AdditionalLoading(_contextUser?: UserInfo): Promise<void>;
    get Countries(): MJCountryEntity[];
    get StateProvinces(): MJStateProvinceEntity[];
    GetCountryByISO2(iso2: string): MJCountryEntity | undefined;
    GetCountryByISO3(iso3: string): MJCountryEntity | undefined;
    GetCountryByName(name: string): MJCountryEntity | undefined;
    GetCountryById(id: string): MJCountryEntity | undefined;
    /**
     * Resolve a country from a text value that could be a name, ISO2, or ISO3 code.
     * Tries ISO2 first (most common), then ISO3, then name match.
     */
    ResolveCountry(value: string): MJCountryEntity | undefined;
    /**
     * Look up a state/province by its Code within a specific country.
     * @param countryId - The country's UUID
     * @param code - The state/province code (e.g., "CO", "ON", "NSW")
     */
    GetStateByCode(countryId: string, code: string): MJStateProvinceEntity | undefined;
    /**
     * Look up a state/province by its Name within a specific country.
     * @param countryId - The country's UUID
     * @param name - The state/province name (e.g., "Colorado", "Ontario")
     */
    GetStateByName(countryId: string, name: string): MJStateProvinceEntity | undefined;
    GetStateById(id: string): MJStateProvinceEntity | undefined;
    /**
     * Resolve a state/province from a text value within a country.
     * Tries code first, then name match.
     */
    ResolveState(countryId: string, value: string): MJStateProvinceEntity | undefined;
    /**
     * Resolve a lat/lng coordinate to its containing country and state/province
     * using point-in-polygon testing against cached BoundaryGeoJSON data.
     * No text matching — purely geometric.
     *
     * @param lat - Latitude (-90 to 90)
     * @param lng - Longitude (-180 to 180)
     * @returns The matched country and state/province, or undefined for each if no match
     */
    ResolvePointToLocation(lat: number, lng: number): GeoPointResolution;
    /**
     * Resolve a lat/lng coordinate to its containing country.
     * Uses bounding-box pre-filtering then ray-casting point-in-polygon.
     */
    ResolvePointToCountry(lat: number, lng: number): MJCountryEntity | undefined;
    /**
     * Resolve a lat/lng coordinate to its containing state/province within a known country.
     * If countryId is not provided, resolves the country first.
     */
    ResolvePointToState(lat: number, lng: number, countryId?: string): MJStateProvinceEntity | undefined;
    /**
     * Batch-resolve multiple lat/lng points in parallel.
     * Each point is resolved independently — ideal for choropleth grouping.
     *
     * @param points - Array of {lat, lng} coordinates
     * @returns Array of GeoPointResolution in the same order as input
     */
    ResolvePoints(points: {
        lat: number;
        lng: number;
    }[]): GeoPointResolution[];
    /**
     * Test if a point falls inside a CachedGeometry (bbox pre-filter + ray-casting).
     */
    private pointInCachedGeometry;
    /**
     * Check if a point is inside a bounding box.
     * BBox format: [minLng, minLat, maxLng, maxLat]
     */
    private pointInBBox;
    /**
     * Ray-casting point-in-polygon for a polygon with rings.
     * First ring is the outer boundary (must be inside).
     * Subsequent rings are holes (must NOT be inside).
     */
    private pointInPolygonRings;
    /**
     * Ray-casting algorithm: cast a horizontal ray from the point eastward,
     * count how many polygon edges it crosses. Odd = inside.
     * Coordinates are [lng, lat] pairs (GeoJSON convention).
     */
    private rayCast;
    /**
     * The Web Worker source code for GeoJSON parsing. This is embedded as a string
     * so we can create an inline Worker via Blob URL — no separate file needed.
     * The worker receives raw BoundaryGeoJSON strings and returns parsed geometries.
     */
    private static readonly GEO_WORKER_SOURCE;
    /**
     * Parse all BoundaryGeoJSON data using a Web Worker (off main thread).
     * Falls back to synchronous parsing if Workers are unavailable.
     */
    private buildGeometryCachesAsync;
    /**
     * Offload GeoJSON parsing to an inline Web Worker.
     * Returns a promise that resolves with the parsed geometry arrays.
     */
    private parseInWorker;
    /**
     * Index state geometries by country for fast lookup.
     * Used after both worker and sync parsing paths.
     */
    private indexStateGeometries;
    /**
     * Synchronous fallback for environments without Web Workers (e.g., Node.js, SSR).
     */
    private buildGeometryCachesSync;
    /**
     * Parse a BoundaryGeoJSON value into a CachedGeometry.
     * Supports GeoJSON Feature, Polygon, and MultiPolygon types.
     * Returns null if the boundary is missing or unparseable.
     * Used by the synchronous fallback path.
     */
    private parseEntityBoundary;
    /**
     * Parse a single Polygon's coordinate rings and compute its bounding box.
     * GeoJSON Polygon coordinates: [ outerRing, ...holeRings ]
     * Each ring is an array of [lng, lat] pairs.
     * Used by the synchronous fallback path.
     */
    private parsePolygonCoordinates;
    private buildLookupMaps;
}
//# sourceMappingURL=GeoDataEngine.d.ts.map