import { Semifunctional } from '../../../../../Class/Semifunctional'
import { PositionObserver } from '../../../../../client/PositionObserver'
import { Component } from '../../../../../client/component'
import { System } from '../../../../../system'
import { Unlisten } from '../../../../../types/Unlisten'
import { PositionObserverCallback } from '../../../../../types/global/IPositionObserver'
import { Component_ } from '../../../../../types/interface/Component'
import { ID_POSITION_OBSERVER } from '../../../../_ids'
import { firstGlobalComponentPromise } from '../../../../globalComponent'

export type I = {
  component: Component_
}

export type O = {
  entry: { x: number; y: number }
}

export default class PositionObserver_ extends Semifunctional<I, O> {
  private _observer: PositionObserver

  constructor(system: System) {
    super(
      {
        fi: ['component', 'opt'],
        fo: [],
        i: ['done'],
        o: ['entry'],
      },
      {
        input: {
          component: {
            ref: true,
          },
        },
      },
      system,
      ID_POSITION_OBSERVER
    )
  }

  private _unlisten: Unlisten

  async f({ component }: I) {
    const {
      api: {
        document: { PositionObserver },
      },
    } = this.__system

    const globalId = component.getGlobalId()

    const component_ = (await firstGlobalComponentPromise(
      this.__system,
      globalId
    )) as Component<HTMLElement>

    if (!this._observer) {
      const observer_callback: PositionObserverCallback = (x, y) => {
        this._output.entry.push({ x, y })
      }

      const observer = new PositionObserver(this.__system, observer_callback)

      this._observer = observer
    }

    const leaf = component_.getFirstRootLeaf() as Component<HTMLElement>

    const { $element } = leaf

    this._observer.observe($element)
  }

  d() {
    // TODO
  }

  public onIterDataInputData(name: string, data: any): void {
    // if (name === 'done') {
    if (this._observer) {
      this._observer.disconnect()
    }

    if (this._unlisten) {
      this._unlisten()
      this._unlisten = undefined
    }

    this._done()

    this.pullInput('done')
    // }
  }
}
