import videojs from 'video.js'
import { VideoPlaylistElement } from '@peertube/peertube-models'
import { PlaylistPluginOptions } from '../../types'
import { PlaylistMenuItem } from './playlist-menu-item'

const Component = videojs.getComponent('Component')

class PlaylistMenu extends Component {
  declare private menuItems: PlaylistMenuItem[]

  declare private readonly userInactiveHandler: () => void
  declare private readonly onMouseEnter: () => void
  declare private readonly onMouseLeave: () => void

  declare private readonly onPlayerCick: (event: Event) => void

  declare options_: PlaylistPluginOptions & videojs.ComponentOptions

  constructor (player: videojs.Player, options?: PlaylistPluginOptions & videojs.ComponentOptions) {
    super(player, options)

    this.menuItems = []

    this.userInactiveHandler = () => {
      this.close()
    }

    this.onMouseEnter = () => {
      this.player().off('userinactive', this.userInactiveHandler)
    }

    this.onMouseLeave = () => {
      this.player().one('userinactive', this.userInactiveHandler)
    }

    this.onPlayerCick = event => {
      let current = event.target as HTMLElement

      do {
        if (
          current.classList.contains('vjs-playlist-menu') ||
          current.classList.contains('vjs-playlist-button')
        ) {
          return
        }

        current = current.parentElement
      } while (current)

      this.close()
    }

    this.el().addEventListener('mouseenter', this.onMouseEnter)
    this.el().addEventListener('mouseleave', this.onMouseLeave)

    this.player().on('click', this.onPlayerCick)
  }

  dispose () {
    this.el().removeEventListener('mouseenter', this.onMouseEnter)
    this.el().removeEventListener('mouseleave', this.onMouseLeave)

    this.player().off('userinactive', this.userInactiveHandler)
    this.player().off('click', this.onPlayerCick)

    for (const item of this.menuItems) {
      item.dispose()
    }

    super.dispose()
  }

  createEl () {
    this.menuItems = []

    const menu = super.createEl('div', {
      className: 'vjs-playlist-menu',
      tabIndex: -1
    })

    const header = super.createEl('div', {
      className: 'header'
    })

    const headerLeft = super.createEl('div')

    const leftTitle = super.createEl('div', {
      innerText: this.options_.playlist.displayName,
      className: 'title'
    })

    const playlistChannel = this.options_.playlist.videoChannel
    const leftSubtitle = super.createEl('div', {
      innerText: playlistChannel
        ? this.player().localize('By {1}', [ playlistChannel.displayName ])
        : '',
      className: 'channel'
    })

    headerLeft.appendChild(leftTitle)
    headerLeft.appendChild(leftSubtitle)

    const tick = super.createEl('div', {
      className: 'cross'
    })
    tick.addEventListener('click', () => this.close())

    header.appendChild(headerLeft)
    header.appendChild(tick)

    const list = super.createEl('ol')

    for (const playlistElement of this.options_.elements) {
      const item = new PlaylistMenuItem(this.player(), {
        element: playlistElement,
        onClicked: () => this.onItemClicked(playlistElement)
      })

      list.appendChild(item.el())

      this.menuItems.push(item)
    }

    menu.appendChild(header)
    menu.appendChild(list)

    this.update()

    return menu
  }

  update () {
    this.updateSelected(this.options_.getCurrentPosition())
  }

  open () {
    this.player().addClass('playlist-menu-displayed')
  }

  close () {
    this.player().removeClass('playlist-menu-displayed')
  }

  updateSelected (newPosition: number) {
    for (const item of this.menuItems) {
      item.setSelected(item.getElement().position === newPosition)
    }
  }

  private onItemClicked (element: VideoPlaylistElement) {
    this.options_.onItemClicked(element)
  }
}

Component.registerComponent('PlaylistMenu', PlaylistMenu)

export { PlaylistMenu }
