import { type LocationSource, type LocationSourceCallbacks } from './locationSource'

function hasLocationPermission(settings: WechatMiniprogram.AuthSetting): boolean {
  const authSettings = settings as Record<string, boolean | undefined>
  return !!authSettings['scope.userLocation']
}

function hasBackgroundLocationPermission(settings: WechatMiniprogram.AuthSetting): boolean {
  const authSettings = settings as Record<string, boolean | undefined>
  return !!authSettings['scope.userLocationBackground']
}

export class RealLocationSource implements LocationSource {
  callbacks: LocationSourceCallbacks
  active: boolean
  boundLocationHandler: ((result: WechatMiniprogram.OnLocationChangeCallbackResult) => void) | null

  constructor(callbacks: LocationSourceCallbacks) {
    this.callbacks = callbacks
    this.active = false
    this.boundLocationHandler = null
  }

  get mode(): 'real' {
    return 'real'
  }

  start(): void {
    if (this.active) {
      this.callbacks.onStatus('后台持续定位进行中')
      return
    }

    wx.getSetting({
      success: (result) => {
        const settings = result.authSetting || {}
        if (hasBackgroundLocationPermission(settings)) {
          this.startBackgroundLocation()
          return
        }

        if (hasLocationPermission(settings)) {
          this.requestBackgroundPermissionInSettings()
          return
        }

        wx.authorize({
          scope: 'scope.userLocation',
          success: () => {
            this.requestBackgroundPermissionInSettings()
          },
          fail: () => {
            this.requestBackgroundPermissionInSettings()
          },
        })
      },
      fail: (error) => {
        const message = error && error.errMsg ? error.errMsg : 'getSetting 失败'
        this.callbacks.onError(`GPS授权检查失败: ${message}`)
      },
    })
  }

  stop(): void {
    if (!this.active) {
      this.callbacks.onStatus('后台持续定位未启动')
      return
    }

    if (typeof wx.offLocationChange === 'function' && this.boundLocationHandler) {
      wx.offLocationChange(this.boundLocationHandler)
    }
    this.boundLocationHandler = null

    wx.stopLocationUpdate({
      complete: () => {
        this.active = false
        this.callbacks.onStatus('后台持续定位已停止')
      },
    })
  }

  destroy(): void {
    if (typeof wx.offLocationChange === 'function' && this.boundLocationHandler) {
      wx.offLocationChange(this.boundLocationHandler)
    }
    this.boundLocationHandler = null

    if (this.active) {
      wx.stopLocationUpdate({ complete: () => {} })
      this.active = false
    }
  }

  requestBackgroundPermissionInSettings(): void {
    this.callbacks.onStatus('请在授权面板开启后台定位')
    wx.openSetting({
      success: (result) => {
        const settings = result.authSetting || {}
        if (hasBackgroundLocationPermission(settings)) {
          this.startBackgroundLocation()
          return
        }

        this.callbacks.onError('GPS启动失败: 未授予后台定位权限')
      },
      fail: (error) => {
        const message = error && error.errMsg ? error.errMsg : 'openSetting 失败'
        this.callbacks.onError(`GPS启动失败: ${message}`)
      },
    })
  }

  startBackgroundLocation(): void {
    wx.startLocationUpdateBackground({
      type: 'wgs84',
      success: () => {
        this.bindLocationListener()
        this.active = true
        this.callbacks.onStatus('后台持续定位已启动')
      },
      fail: (error) => {
        const message = error && error.errMsg ? error.errMsg : 'startLocationUpdateBackground 失败'
        this.callbacks.onError(`GPS启动失败: ${message}`)
      },
    })
  }

  bindLocationListener(): void {
    if (this.boundLocationHandler) {
      return
    }

    this.boundLocationHandler = (result) => {
      this.callbacks.onLocation({
        latitude: result.latitude,
        longitude: result.longitude,
        accuracy: result.accuracy,
        speed: result.speed,
        timestamp: Date.now(),
        sourceMode: 'real',
      })
    }

    wx.onLocationChange(this.boundLocationHandler)
  }
}
