import { default as default_2 } from 'react';
import { LoaderOptions } from '@googlemaps/js-api-loader';
import { ReactNode } from 'react';
import { ReactPortal } from 'react';
import { RefObject } from 'react';

export declare const Circle: (props: CircleProps) => null;

export declare interface CircleProps extends Omit<google.maps.CircleOptions, 'map'> {
    _instance?: google.maps.Circle;
    center?: LatLng | null;
    radius?: number;
    visible?: boolean;
    draggable?: boolean;
    editable?: boolean;
    clickable?: boolean;
    onClick?: MapCircleEventHandler;
    onDblClick?: MapCircleEventHandler;
    onContextMenu?: MapCircleEventHandler;
    onChange?: MapCircleEventHandler;
    onDragStart?: MapCircleEventHandler;
    onDrag?: MapCircleEventHandler;
    onDragEnd?: MapCircleEventHandler;
    onMouseDown?: MapCircleEventHandler;
    onMouseMove?: MapCircleEventHandler;
    onMouseOut?: MapCircleEventHandler;
    onMouseOver?: MapCircleEventHandler;
    onMouseUp?: MapCircleEventHandler;
}

export declare const Control: (props: ControlProps) => ReactPortal;

export declare enum ControlPosition {
    TOP_LEFT = "TOP_LEFT",
    TOP_CENTER = "TOP_CENTER",
    TOP_RIGHT = "TOP_RIGHT",
    LEFT_TOP = "LEFT_TOP",
    LEFT_CENTER = "LEFT_CENTER",
    LEFT_BOTTOM = "LEFT_BOTTOM",
    RIGHT_TOP = "RIGHT_TOP",
    RIGHT_CENTER = "RIGHT_CENTER",
    RIGHT_BOTTOM = "RIGHT_BOTTOM",
    BOTTOM_LEFT = "BOTTOM_LEFT",
    BOTTOM_CENTER = "BOTTOM_CENTER",
    BOTTOM_RIGHT = "BOTTOM_RIGHT",
    INLINE_START_BLOCK_START = "INLINE_START_BLOCK_START",
    INLINE_START_BLOCK_CENTER = "INLINE_START_BLOCK_CENTER",
    INLINE_START_BLOCK_END = "INLINE_START_BLOCK_END",
    INLINE_END_BLOCK_START = "INLINE_END_BLOCK_START",
    INLINE_END_BLOCK_CENTER = "INLINE_END_BLOCK_CENTER",
    INLINE_END_BLOCK_END = "INLINE_END_BLOCK_END",
    BLOCK_START_INLINE_START = "BLOCK_START_INLINE_START",
    BLOCK_START_INLINE_CENTER = "BLOCK_START_INLINE_CENTER",
    BLOCK_START_INLINE_END = "BLOCK_START_INLINE_END",
    BLOCK_END_INLINE_START = "BLOCK_END_INLINE_START",
    BLOCK_END_INLINE_CENTER = "BLOCK_END_INLINE_CENTER",
    BLOCK_END_INLINE_END = "BLOCK_END_INLINE_END"
}

export declare interface ControlProps {
    id: string;
    position: ControlPosition;
    className?: string;
    children?: ReactNode;
}

/**
 * create marker that can render on google map
 * @param WrappedMarker
 */
export declare function createMarker<M extends MarkerProps, T extends object>(WrappedMarker: default_2.ComponentType<T>): default_2.FunctionComponent<M & T>;

declare type Draggable<T = any> = {
    /** if set true, element is draggable */
    draggable?: boolean;
    onDrag?(e: MouseEvent, params: T): void;
    onDragStart?(e: MouseEvent, params: T): void;
    onDragEnd?(e: MouseEvent, params: T): void;
};

/** use with useGoogleMap */
export declare const GoogleMap: default_2.NamedExoticComponent<GoogleMapProps>;

declare interface GoogleMapApi {
    map: google.maps.Map;
    maps: typeof google.maps;
}

export declare interface GoogleMapProps {
    className?: string;
    style?: default_2.CSSProperties;
    api?: GoogleMapApi;
    containerRef: RefObject<HTMLDivElement>;
    children?: default_2.ReactNode;
    classNames?: {
        map?: string;
        children?: string;
    };
}

export declare type GoogleMapStat = 'loading' | 'loaded' | 'error';

declare type LatLng = google.maps.LatLngLiteral | google.maps.LatLng;

export declare type MapCircleEventHandler = MapsEventHandler<[google.maps.Circle]>;

export declare type MapOverlayEventHandler = MapsEventHandler<[google.maps.GroundOverlay]>;

export declare type MapPolygonEventHandler = MapsEventHandler<[google.maps.Polygon]>;

export declare type MapPolylineEventHandler = MapsEventHandler<[google.maps.Polyline]>;

declare type MapsEventHandler<D extends any[] = [], Event = google.maps.MapMouseEvent> = (e: Event, ...args: D) => void;

/**
 * Display custom marker on map
 */
export declare const Marker: (props: MarkerProps) => default_2.JSX.Element | null;

export declare interface MarkerProps {
    /** latitude */
    lat: number;
    /** longitude */
    lng: number;
    /** z-index */
    zIndex?: number;
    /** marker origin */
    origin?: OverlayViewOrigin;
    /** marker origin offset */
    originOffset?: number | OverlayViewOriginOffset;
    /** your custom marker element */
    children?: ReactNode;
    /** if set true, element is draggable */
    draggable?: boolean;
    /** drag event callback */
    onDrag?(e: MouseEvent, data: {
        latlng: LatLng;
    }): void;
    /** dragstart event callback */
    onDragStart?(e: MouseEvent, data: {
        latlng: LatLng;
    }): void;
    /** dragend event callback */
    onDragEnd?(e: MouseEvent, data: {
        latlng: LatLng;
    }): void;
}

export declare const Overlay: (props: OverlayProps) => null;

export declare interface OverlayProps extends Omit<google.maps.GroundOverlayOptions, 'map'> {
    image: string;
    bounds: [LatLng, LatLng];
    opacity?: number;
    clickable?: boolean;
    onClick?: MapOverlayEventHandler;
    onDblClick?: MapOverlayEventHandler;
}

export declare const OverlayView: (props: OverlayViewProps) => default_2.ReactPortal | null;

declare type OverlayViewDraggable = Draggable<{
    latlng: LatLng;
}>;

declare type OverlayViewOrigin = 'center' | 'bottomCenter';

declare type OverlayViewOriginOffset = [number, number];

export declare interface OverlayViewProps extends OverlayViewDraggable {
    className?: string;
    pane?: PaneType;
    position: LatLng;
    children?: default_2.ReactNode;
    zIndex?: number;
    origin?: OverlayViewOrigin;
    originOffset?: OverlayViewOriginOffset;
    clickable?: boolean;
    onClick?: (event: google.maps.MapMouseEvent) => void;
}

/**
 * paneType z-index sequence: floatPane > overlayMouseTarget > markerLayer > overlayLayer > mapPane
 */
declare type PaneType = keyof NonNullable<google.maps.MapPanes>;

export declare const Polygon: (props: PolygonProps) => null;

export declare interface PolygonProps extends Omit<google.maps.PolygonOptions, 'map'> {
    _instance?: google.maps.Polygon;
    paths?: LatLng[];
    visible?: boolean;
    editable?: boolean;
    draggable?: boolean;
    clickable?: boolean;
    onClick?: MapPolygonEventHandler;
    onContextMenu?: MapPolygonEventHandler;
    onDblClick?: MapPolygonEventHandler;
    onDragStart?: MapPolygonEventHandler;
    onDrag?: MapPolygonEventHandler;
    onDragEnd?: MapPolygonEventHandler;
    onMouseOut?: MapPolygonEventHandler;
    onMouseOver?: MapPolygonEventHandler;
    onMouseUp?: MapPolygonEventHandler;
    onMouseDown?: MapPolygonEventHandler;
    onMouseMove?: MapPolygonEventHandler;
}

export declare const Polyline: (props: PolylineProps) => null;

export declare interface PolylineProps extends Omit<google.maps.PolylineOptions, 'map'> {
    _instance?: google.maps.Polyline;
    /** polyline path */
    path?: LatLng[];
    clickable?: boolean;
    draggable?: boolean;
    editable?: boolean;
    geodesic?: boolean;
    visible?: boolean;
    zIndex?: number | null;
    onMouseOut?: MapPolylineEventHandler;
    onMouseOver?: MapPolylineEventHandler;
    onMouseUp?: MapPolylineEventHandler;
    onMouseDown?: MapPolylineEventHandler;
    onMouseMove?: MapPolylineEventHandler;
    onClick?: MapPolylineEventHandler;
    onContextMenu?: MapPolylineEventHandler;
    onDblClick?: MapPolylineEventHandler;
    onDragStart?: MapPolylineEventHandler;
    onDrag?: MapPolylineEventHandler;
    onDragEnd?: MapPolylineEventHandler;
}

/**
 * load google map and create map instance
 * @param options
 * @returns
 */
export declare function useGoogleMap(options: UseGoogleMapOptions): {
    api: GoogleMapApi | undefined;
    ref: RefObject<HTMLDivElement>;
    stat: GoogleMapStat | undefined;
    err: any;
};

export declare type UseGoogleMapOptions = {
    /** loader option, include apiKey, you should keep the ref stable */
    loader: LoaderOptions;
    /** map initial option, you should keep the ref stable */
    map?: google.maps.MapOptions;
};

/**
 * use GoogleMap context, you should use it inside `<GoogleMap />` components
 * @returns
 */
export declare function useMapCtx(): {
    map: google.maps.Map;
    maps: typeof google.maps;
};

export { }
