import Taro from '@tarojs/taro';

import { isNaN } from 'lodash-es';

import { CITY_CODE_TO_NAME_MAP, COUNTY_CODE_TO_NAME_MAP, PROVINCE_CODE_TO_NAME_MAP } from '@/constants/city';
import http from '@/http';
import { API } from '@/http/api';
import store from '@/store';
import { setLocationInfo } from '@/store/actions';
import { selectLocation } from '@/store/selector';
import { GetCityCodeRequest, LocationInfo } from '@/types/location';

import { authorize, getWxSetting } from './wx';

let locationInfo: Taro.getLocation.SuccessCallbackResult | null = null;
let waitAuthorizeLocationPromise: ReturnType<typeof authorize> | null = null;
const VALID_DISTANCE_KM = 999;

export const isValidLocation = (location: LocationInfo) => {
  if (!location) {
    return false;
  }
  return !isNaN(Number(location.latitude)) && !isNaN(Number(location.longitude));
};

export const isValidDistance = (distance: number) => distance < 1000 * VALID_DISTANCE_KM;

export const isNotNeedAuthorizeLocation = () => getWxSetting('scope.userLocation');

export const calcDistance = (distance: number, fractionDigits = 2) => {
  if (isValidDistance(distance)) {
    return `${(distance / 1000).toFixed(fractionDigits)}km`;
  }
  return '999km';
};

export const getCurrentCity = () => {
  const cityCode = selectLocation(store.getState()).cityCode;
  return CITY_CODE_TO_NAME_MAP.get(cityCode) || '';
};

export const getCityValues = (codes: string[] = [], separator: string = '') => {
  const [province, city, county] = codes;
  const values: string[] = [];
  if (province) {
    const v = PROVINCE_CODE_TO_NAME_MAP.get(province);
    v && values.push(v);
  }
  if (city) {
    const v = CITY_CODE_TO_NAME_MAP.get(city);
    v && values.push(v);
  }
  if (county) {
    const v = COUNTY_CODE_TO_NAME_MAP.get(county);
    v && values.push(v);
  }
  return values.join(separator);
};

export async function waitLocationAuthorizeHidden() {
  if (!waitAuthorizeLocationPromise) {
    return;
  }
  await waitAuthorizeLocationPromise;
}

/**
 * 获取经纬度信息
 * @param opts
 * @returns
 */
export async function getWxLocation(
  opts?: Taro.getLocation.Option,
  force = true
): Promise<Taro.getLocation.SuccessCallbackResult | null> {
  if (locationInfo?.latitude) return Promise.resolve(locationInfo);

  const notNeedAuthorize = await isNotNeedAuthorizeLocation();

  if (!notNeedAuthorize) {
    waitAuthorizeLocationPromise = authorize('scope.userLocation', '请授权获取位置权限', force);
    if (!(await waitAuthorizeLocationPromise)) {
      return null;
    }
  }
  // 重新获取位置信息
  return new Promise(resolve => {
    try {
      Taro.getLocation({
        type: 'wgs84',
        ...opts,
        success: res => {
          setTimeout(() => {
            locationInfo = null;
          }, 31000);
          if (res?.latitude) {
            locationInfo = res;
            return resolve(res);
          }
          resolve(null);
        },
        fail: () => resolve(null),
      });
    } catch (e) {
      console.error(e);
    }
  });
}

export async function requestLocation(force: boolean = false) {
  const data = {} as GetCityCodeRequest;
  const lgInfo = await getWxLocation({}, force);
  if (!lgInfo) {
    return;
  }
  if (lgInfo?.latitude && lgInfo?.longitude) {
    data.latitude = lgInfo.latitude;
    data.longitude = lgInfo.longitude;
  }

  const location = await http.post<LocationInfo>(API.LOCATION, {
    data,
    contentType: 'application/x-www-form-urlencoded',
  });
  if (!location.latitude) {
    location.latitude = data.latitude;
  }
  if (!location.longitude) {
    location.longitude = data.longitude;
  }
  store.dispatch(setLocationInfo(location));
  return location;
}
