import {
  Pose,
  TrackingEvent,
  TrackableObject,
  TrackingStorage,
  DEFAULT_POSE_THRESHOLD,
  TrackingEventQueue,
  TRACKING_EVENT_TYPES
} from './robotics-types'
import { TrackableObjectImpl } from './trackable-object'

const debug = require('debug')('aidoop:robotics:tracking-storage')

export class TrackingEventQueueImpl implements TrackingEventQueue {
  trackingEvents: TrackingEvent[]
  registeredTypes: TRACKING_EVENT_TYPES[]

  constructor() {
    this.trackingEvents = []
    this.registeredTypes = []
  }

  reset() {
    this.trackingEvents = []
    this.registeredTypes = []
  }

  registerType(registeredEvent: TRACKING_EVENT_TYPES) {
    this.registeredTypes.push(registeredEvent)
  }

  deregisterType(registeredEvent: TRACKING_EVENT_TYPES) {
    let idx = this.registeredTypes.indexOf(registeredEvent)
    if (idx > -1) {
      this.registeredTypes.splice(idx, 1)
    }
  }

  queue(trackingEvent: TrackingEvent) {
    if (this.registeredTypes.indexOf(trackingEvent.type) >= 0) {
      this.trackingEvents.push(trackingEvent)
    }
  }

  dequeue() {
    return this.trackingEvents.shift()
  }

  count() {
    return this.trackingEvents.length
  }

  instanceofTrackingEvent(object: any): object is TrackingEvent {
    return 'type' in object
  }
}

export class ROIStateStorageImpl implements TrackingStorage {
  states: { [id: string]: TrackableObject } = {}
  eventQueue: { [roi: string]: TrackingEventQueue } = {}

  getObjectState(id) {
    const state = this.states[id]

    if (!state) {
      debug('not found', id, this.states)
    }

    return {
      ...state
    }
  }

  getROIState(roi) {
    return Object.keys(this.states)
      .map(id => this.states[id])
      .filter(obj => obj.roi == roi)
      .sort((obj1, obj2) => (obj1.id > obj2.id ? 1 : -1))
      .map(obj => {
        return {
          ...obj
        }
      })
  }

  updateObjectState(id, roi, pose?: Pose, threshold?: Pose) {
    if (!this.states[id]) {
      this.states[id] = new TrackableObjectImpl(id)
    }
    if (!this.eventQueue[roi]) {
      this.eventQueue[roi] = new TrackingEventQueueImpl()
      this.eventQueue[roi].registerType(TRACKING_EVENT_TYPES.IN)
      this.eventQueue[roi].registerType(TRACKING_EVENT_TYPES.OUT)
    }

    var changes = this.states[id].update(
      roi,
      pose,
      threshold
        ? {
            ...DEFAULT_POSE_THRESHOLD,
            ...threshold
          }
        : DEFAULT_POSE_THRESHOLD
    )

    //if (changes !== null) changes.forEach(change => this.publish(change))
    if (changes !== null) changes.forEach(change => this.setROIEvent(change))
  }

  publish(event: TrackingEvent) {
    console.log('\n\n\n\nevent', event)
  }

  setROIEvent(event: TrackingEvent) {
    // which roi(camera) this event happens in??
    if (event.object.roi.toString() !== '') {
      this.eventQueue[event.object.roi.toString()].queue(event)
    } else if (event.object.roi.toString() !== '') {
      this.eventQueue[event.from.roi.toString()].queue(event)
    } else if (event.object.roi.toString() !== '') {
      this.eventQueue[event.to.roi.toString()].queue(event)
    }
  }

  getROIEvent(roi) {
    return this.eventQueue[roi]?.dequeue()
  }
}
