import Taro from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import dateformat from 'dateformat'

import classNames from 'classnames'
import PropTypes, { InferProps } from 'prop-types'
import CtsComponent from '../../common/component'
import { CtsCheckingProps, CtsCheckingState } from '@/types/checking'

/**
 * 考勤打卡组件
 */
export default class CtsChecking extends CtsComponent<CtsCheckingProps, CtsCheckingState> {
  // static options = {
  //   addGlobalClass: true
  // }

  public static defaultProps: CtsCheckingProps
  public static propTypes: InferProps<CtsCheckingProps>

  public constructor(props: CtsCheckingProps) {
    super(props)
    this.state = {
      latitude: 0,
      longitude: 0,
      address: '',
      distance: 0,
      interval: null
    }
  }

  public componentWillMount(): void {}

  public componentDidMount(): void {
    console.log('添加获取地理位置定时器：componentDidMount')
    // 获取当前的地理位置
    this.getLocationInit()
  }

  public componentDidShow(): void {
    console.log('添加获取地理位置定时器：componentDidShow')
    // 获取当前的地理位置
    this.getLocationInit()
  }

  public componentDidHide(): void {
    // 销毁获取地理位置定时器
    // console.log('销毁获取地理位置定时器：componentDidHide')
    // this.clearInterval()

    // 取消监听实时地理位置变化事件
    console.log('取消监听实时地理位置变化事件：componentDidHide')
    this.offLocationChange()
  }

  public componentWillUnmount(): void {
    // 销毁获取地理位置定时器
    // console.log('销毁获取地理位置定时器：componentWillUnmount')
    // this.clearInterval()

    // 取消监听实时地理位置变化事件
    console.log('取消监听实时地理位置变化事件：componentWillUnmount')
    this.offLocationChange()
  }

  // 销毁获取地理位置定时器
  // private clearInterval(): void {
  //   // const { interval } = this.state

  //   // 销毁获取地理位置定时器
  //   // clearInterval(interval)

  //   // 取消监听实时地理位置变化事件
  //   this.offLocationChange()
  // }

  // 取消监听实时地理位置变化事件
  private offLocationChange(): void {
    Taro.offLocationChange(this.onLocationChange)
  }

  // 获取当前的地理位置
  private getLocationInit(): void {
    const that = this

    // 获取当前的地理位置
    // this.getLocation()

    // // 每5秒钟刷新当前位置
    // let interval = setInterval(() => {
    //   // 获取当前的地理位置
    //   this.getLocation()
    // }, 5000)
    // this.setState({ interval })

    Taro.getSetting({
      success(res) {
        console.log('getSetting', res)

        if (!res.authSetting['scope.userLocationBackground']) {

          Taro.showToast({
            title: '请选择在"在使用小程序期间和离开小程序后"，否则无法获取地理位置',
            icon: 'none',
            duration: 5000,
            mask: false
          })

            // 提前向用户发起授权请求。调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据，但不会实际调用对应接口。如果用户之前已经同意授权，则不会出现弹窗，直接返回成功。
          Taro.authorize({
            scope: 'scope.userLocationBackground',
            success() {
              Taro.showLoading({ title: '定位中...', mask: true })
              // 监听实时地理位置 - 开启
              that.startLocationUpdateBackground()
            },
            fail() {
              Taro.showToast({
                title: '授权失败，点击右上角设置位置为使用时和离开后',
                icon: 'none',
                duration: 5000,
                mask: false,
                success() {
                  // Taro['common'].goBack(1, 5000)
                }
              })
            }
          })
        } else {
          Taro.showLoading({ title: '定位中...', mask: true })
          // 监听实时地理位置 - 开启
          that.startLocationUpdateBackground()
        }
      }
    })
  }

  // 监听实时地理位置 - 开启
  private startLocationUpdateBackground(): void {
    const that = this
    Taro.startLocationUpdateBackground({
      success() {
        Taro.onLocationChange(that.onLocationChange.bind(that))
      }
    })
  }

  // 监听实时地理位置
  private onLocationChange(res): void {
    let that = this
    const { lat, lng } = this.props

    that.setState({
      latitude: res.latitude,
      longitude: res.longitude,
      distance: Math.round(that.getFlatternDistance(res.latitude, res.longitude, lat, lng))
    }, () => {
      const { latitude, longitude, distance } = that.state
      console.log('经度：', longitude, '纬度：', latitude, '两点的距离：', distance)

      // 获取当前位置，逆地址解析
      Taro['common'].reverseGeocoder({ latitude, longitude }).then(res => {
        that.setState({
          address: res.result.address
        })
        Taro.hideLoading()
      }).catch(err => {
        console.error(err)
        Taro.hideLoading()
      })
    })
  }

  // 刷新定位
  private getLocationRefresh(): void {
    Taro.showLoading({ title: '定位中...', mask: true })

    // 获取当前的地理位置
    // this.getLocation()

    Taro.onLocationChange(this.onLocationChange)
  }

  // 获取当前的地理位置
  // private getLocation(): void {
  //   let that = this
  //   const { lat, lng } = this.props

  //   // 获取地理位置
  //   Taro.getLocation({
  //     type: 'gcj02',
  //     isHighAccuracy: true,
  //     success(res) {
  //       that.setState({
  //         latitude: res.latitude,
  //         longitude: res.longitude,
  //         distance: Math.round(that.getFlatternDistance(res.latitude, res.longitude, lat, lng))
  //       }, () => {
  //         const { latitude, longitude, distance } = that.state
  //         console.log('经度：', longitude, '纬度：', latitude, '两点的距离：', distance)

  //         // 获取当前位置，逆地址解析
  //         Taro['common'].reverseGeocoder({ latitude, longitude }).then(res => {
  //           that.setState({
  //             address: res.result.address
  //           })
  //           Taro.hideLoading()
  //         }).catch(err => {
  //           console.error(err)
  //           Taro.hideLoading()
  //         })
  //       })
  //     },
  //     fail(err) {
  //       console.error(err)
  //       Taro.hideLoading()
  //     }
  //   })
  // }

  private getRad(d: number) {
    return d * Math.PI / 180.0
  }

  // 根据两点的经纬度，计算两点的距离
  private getFlatternDistance(lat1: number, lng1: number, lat2: number, lng2: number) {
    var EARTH_RADIUS = 6378137.0    // 单位M

    var f = this.getRad((lat1 + lat2) / 2)
    var g = this.getRad((lat1 - lat2) / 2)
    var l = this.getRad((lng1 - lng2) / 2)

    var sg = Math.sin(g)
    var sl = Math.sin(l)
    var sf = Math.sin(f)

    var s, c, w, r, d, h1, h2
    var a = EARTH_RADIUS
    var fl = 1 / 298.257

    sg = sg * sg;
    sl = sl * sl;
    sf = sf * sf;

    s = sg * (1 - sl) + (1 - sf) * sl;
    c = (1 - sg) * (1 - sl) + sf * sl;

    w = Math.atan(Math.sqrt(s / c));
    r = Math.sqrt(s * c) / w
    d = 2 * w * a
    h1 = (3 * r - 1) / 2 / c
    h2 = (3 * r + 1) / 2 / s

    return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg)) || 0;
  }

  // 点击打卡
  private checkingFn() {
    const { distance, latitude, longitude, address } = this.state
    const { mode, distanceScope } = this.props

    let data = { mode, latitude, longitude, address }
    if (distance <= distanceScope) {
      this.props.checkingFn(data)
    } else {
      Taro.showToast({ title: '当前不在考勤范围内，请前往考勤范围内打卡', icon: 'none' })
    }
  }

  public render(): JSX.Element {
    const { distance } = this.state
    const { className, time, distanceScope, title } = this.props

    return (
      <View className={classNames('cts-checking', className)}>
        <View className='item-checking-time' onClick={this.checkingFn.bind(this)}>
          <View className='time'>{dateformat(time, 'HH:MM:ss')}</View>
          <View className='text'>{title}</View>
        </View>
        <View className='item-checking-text'>
          {
            distance <= distanceScope ?
              <View className='text1'>当前位置已在范围内</View>
              :
              <View className='text2'>
                <Text>当前不在考勤范围内</Text>
                <Text onClick={this.getLocationRefresh}>刷新定位</Text>
              </View>
          }
        </View>
      </View>
    )
  }
}

CtsChecking.defaultProps = {
  time: new Date(),
  mode: 'amOnWork',
  title: '',
  lat: 0,
  lng: 0,
  distanceScope: 100,
  checkingFn() { }
}

CtsChecking.propTypes = {
  time: PropTypes.any,
  mode: PropTypes.string,
  title: PropTypes.string,
  lat: PropTypes.number,
  lng: PropTypes.number,
  distanceScope: PropTypes.number,
  checkingFn: PropTypes.func
}
