import { NativeModules, NativeEventEmitter, AppState, AppStateStatus } from 'react-native';

const { AMapLocation } = NativeModules;
const eventEmitter = new NativeEventEmitter(AMapLocation);

export class ALocationProxy {
    listener: ALocationListner;
    constructor(listener: ALocationListner) {
        this.listener = listener;
    }
    public stop(): void {
        const index = listeners.indexOf(this.listener);
        if (index > -1) {
            listeners.splice(index, 1);
        }
    }
}

class ALocationListner {
    once: boolean;
    background: boolean;
    callback: (location: ALocation) => void;
    callbackTarget: any;

    public constructor(once: boolean, backgroud: boolean, callback: (location: ALocation) => void) {
        this.once = once;
        this.background = backgroud;
        this.callback = callback;
    }

    public apply(location: ALocation): void {
        if (this.callback) {
            this.callback(location);
        }
    }
}

interface LocationError {
    readonly code: number;
    readonly info: string;
    readonly details: string;
}

interface LocationQualityReport {
    /**
     * 获取提示语义,状态良好时，返回的是内容为空 根据当前的质量报告，给出相应的建议
     */
    readonly adviseMessage: string;
    /**
     * 获取当前的卫星数， 只有在非低功耗模式下此值才有效
     */
    readonly gpsSatellites: number;
    /**
     * 获取卫星状态信息，只有在非低功耗模式下此值才有效
     */
    readonly gpsStatus: number;
    /**
     * 获取网络定位时的网络耗时 单位：毫秒
     */
    readonly netUseTime: number;
    /**
     * 获取网络连接类型（2G、3G、4G、WIFI)
     */
    readonly networkType: string;
    /**
     * 是否安装了高危位置模拟软件 首次定位可能没有结果
     */
    readonly isInstalledHighDangerMockApp: boolean;
    /**
     * wifi开关是否打开 如果wifi关闭建议打开wifi开关，提高定位质量
     */
    readonly isWifiAble: boolean;
}
export interface ALocation {
    /**
     *
     */
    readonly error: LocationError;
    /**
     * 获取定位结果来源
     */
    readonly type: number;
    /**
     * 获取纬度
     */
    readonly latitude: number;
    /**
     * 获取纬度
     */
    readonly longitude: number;
    /**
     * 获取定位精度
     */
    readonly accuracy: number;
    /**
     * 获取定位提供者
     */
    readonly provider: string;
    /**
     * 获取速度
     */
    readonly speed: number;
    /**
     * 获取角度
     */
    readonly bearing: number;
    /**
     * 获取当前可用卫星数量, 仅在卫星定位时有效
     */
    readonly satellites: number;
    /**
     * 获取国家名称
     */
    readonly country: string;
    /**
     * 获取城市名称
     */
    readonly city: string;
    /**
     * 获取城市编码
     */
    readonly cityCode: string;
    /**
     * 获取区域名称
     */
    readonly district: string;
    /**
     * 获取区域编码
     */
    readonly districtCode: string;
    /**
     * 获取地址
     */
    readonly address: string;
    /**
     * 获取兴趣点
     */
    readonly poiName: string;
    /**
     * 获取定位时间
     */
    readonly time: number;
    /**
     * 获取定位质量报告
     */
    readonly quality: LocationQualityReport;
}

export type ALocationCallback = (location: ALocation) => void;

export class ALocationClientOptions {
    httpTimeout?: number;
    interval?: number;
    cacheEnabled?: boolean;
    mode?: 'Battery_Saving' | 'Device_Sensors' | 'Hight_Accuracy';
    protocol?: 'HTTP' | 'HTTPS';
    mockEnabled?: boolean;
    needAddress?: boolean;
    sensorEnable?: boolean;
    wifiScan?: boolean;
}

/** 当前是否在后台运行 */
var isBackground: boolean = false;
/** 当前是否在后台定位 */
var isBackgroundLocation: boolean = false;

var listeners: ALocationListner[] = [];

var locationOptions: ALocationClientOptions = {};

/** 是否已经开始定位*/
var isStarted = false;

const start = () => {
    if (isStarted) {
        return;
    }
    isStarted = true;
    AMapLocation.start(locationOptions);
};
const stop = () => {
    isStarted = false;
    AMapLocation.stop();
};
const appStateChangeListner = (status: AppStateStatus) => {
    isBackground = status !== 'active';
    console.log(`------>AMapLocation: The application's status is ${status}`);
    if (!isBackground) {
        console.log(`------>AMapLocation: enter forground disable background location`);
        AMapLocation.enabledBackground(false);
    } else if (isBackgroundLocation) {
        console.log(`------>AMapLocation: enter background, enabled background location`);
        AMapLocation.enabledBackground(true);
    }
};

const amapLocationListner = (location: ALocation) => {
    for (const listener of listeners) {
        if (!listener.background && isBackground) {
            continue;
        }
        listener.apply(location);
    }
    // 删除once的listener
    listeners = listeners.filter((listener) => !listener.once);
    // 没有后台监听
    if (isBackgroundLocation && !listeners.find((l) => l.background)) {
        isBackgroundLocation = false;
        console.log(`------>AMapLoaction: There has't background location callback, will stop backgroud location`);
    }
    // 已经没有位置监听，自动关闭位置服务
    if (!listeners.length) {
        console.log(`------>AMapLoaction: There has't location callback, will auto stop the location service`);
        stop();
    }
};

/**
 * 高德定位服务
 */
export class ALocationClient {
    private constructor() {
        AppState.addEventListener('change', appStateChangeListner);
        eventEmitter.addListener('amap_location', amapLocationListner);
    }

    private static instance: ALocationClient;

    /**
     * 获取ALoaction的单例
     */
    public static getInstace(): ALocationClient {
        if (!ALocationClient.instance) {
            ALocationClient.instance = new ALocationClient();
        }
        return ALocationClient.instance;
    }

    /**
     * 当前是否已启用后台定位
     */
    public get isBackground(): boolean {
        return isBackgroundLocation;
    }

    /**
     * 获取或设置定位选项
     */
    public set options(options: ALocationClientOptions) {
        locationOptions = options;
    }

    public get options(): ALocationClientOptions {
        return locationOptions;
    }

    public location(callback: ALocationCallback, background: boolean = false): ALocationProxy {
        this.checkIsAutoStop();
        if (background && !isBackgroundLocation) {
            isBackgroundLocation = true;
        }
        const listener: ALocationListner = new ALocationListner(false, background, callback);
        listeners.push(listener);
        return new ALocationProxy(listener);
    }

    public locationOnce(callback: ALocationCallback): void {
        this.checkIsAutoStop();
        listeners.push(new ALocationListner(true, false, callback));
    }

    private checkIsAutoStop(): void {
        if (!isStarted) {
            start();
        }
    }
}
