import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs'

import nearest from '@turf/nearest-point'
import distance from '@turf/distance'
import bearing from '@turf/bearing'
import { Feature } from 'maplibre-gl'
import { AbsoluteOrientationSensor } from 'motion-sensors-polyfill/src/motion-sensors'

import { ConfigService } from './config.service'
import { FeatureTarget } from './models'
import { DataService } from './data.service'
import { FeatureCollection } from 'geojson'


@Injectable({
  providedIn: 'root'
})
export class FeatureFinderService {
  sensor: AbsoluteOrientationSensor
  constructor(
    public dataService: DataService,
    public configService: ConfigService,
  ) {
    this.sensor = new AbsoluteOrientationSensor()
    this.sensor.start()
    this.sensor.onerror = event => {
        console.error("Error with AbsoluteOrientationSensor", event)
    }
    this.sensor.addEventListener('reading', () => {
      const q = this.sensor.quaternion
      const heading = Math.atan2(2*q[0]*q[1] + 2*q[2]*q[3], 1-2*q[1]*q[1] - 2*q[2]*q[2])*(180/Math.PI)
      this.orientation.next(heading)
    })
    this.orientation$.subscribe(
      orientation => this.findNewFeature()
    )
    this.findNewFeature()
  }

  public hasDirection = new BehaviorSubject<boolean>(true)
  public hasDirection$ = this.hasDirection.asObservable()
  public direction = new BehaviorSubject<number>(undefined)
  public direction$ = this.direction.asObservable()
  public distance = new BehaviorSubject<number>(undefined)
  public distance$ = this.distance.asObservable()
  public orientation = new BehaviorSubject<number>(undefined)
  public orientation$ = this.orientation.asObservable()
  public location: GeolocationPosition

  findNewFeature(location?: GeolocationPosition): FeatureTarget|undefined {
    if (location) {
      this.location = location
    }
    else {
      location = this.location
    }

    if (Object.keys(this.dataService.treeFeatures.getValue()).length != 0 && location) {
      let loc = {
        "type": "Feature",
        "properties": {},
        "geometry": {
          "type": "Point",
          "coordinates": [location.coords.longitude, location.coords.latitude]
        }
      }
      let trees: FeatureCollection = <any>this.dataService.treeFeatures.getValue()
      if (trees['features'].length == 0) {
        return undefined
      }
      let nt = nearest(<any>loc, <any>trees)
      let d = distance(<any>loc, nt, {units: 'meters'})
      let b = bearing(<any>loc, nt)
      if (d < this.configService.conf.value.alertDistance) {
        this.distance.next(d)
        if (this.orientation.value != undefined) {
          this.hasDirection.next(true)
          this.direction.next(b + this.orientation.value)
        }
        else {
          this.hasDirection.next(false)
        }
        return new FeatureTarget(<Feature><any>nt, d, )
      }
      else {
        this.distance.next(undefined)
        return undefined
      }
    }
    this.distance.next(undefined)
    return undefined
  }
}
