// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
//
// SPDX-License-Identifier: AGPL-3.0-only

import type { RegisterClientOptions } from '@peertube/peertube-types/client'
import type { Video } from '@peertube/peertube-types'
import type { ProsodyListRoomsResult } from 'shared/lib/types'
import { getBaseRoute } from './utils/uri'

interface ActionPluginSettingsParams {
  npmName: string
}

function register (clientOptions: RegisterClientOptions): void {
  const { registerHook, registerSettingsScript, peertubeHelpers } = clientOptions

  registerHook({
    target: 'action:admin-plugin-settings.init',
    handler: ({ npmName }: ActionPluginSettingsParams) => {
      if (npmName !== PLUGIN_CHAT_PACKAGE_NAME) {
        console.log(`[peertube-plugin-livechat] Settings for ${npmName}, not ${PLUGIN_CHAT_PACKAGE_NAME}. Returning.`)
        return
      }
      console.log('[peertube-plugin-livechat] Initializing diagnostic button')
      const diagButtons = document.querySelectorAll('.peertube-plugin-livechat-launch-diagnostic')
      diagButtons.forEach(diagButton => {
        if (diagButton.hasAttribute('href')) { return }
        // TODO: use a modal instead of a target=_blank
        diagButton.setAttribute('href', getBaseRoute(clientOptions) + '/settings/diagnostic')
        diagButton.setAttribute('target', '_blank')
      })
      console.log('[peertube-plugin-livechat] Initializing prosody-list-rooms button')
      const listRoomsButtons: NodeListOf<HTMLAnchorElement> =
        document.querySelectorAll('.peertube-plugin-livechat-prosody-list-rooms-btn')

      try {
        // Trying to copy Computed CSS for an input[type=submit] to the list rooms button
        const tmpButton = document.querySelector('#content input[type=submit]')
        if (window.getComputedStyle && tmpButton) {
          const styles = window.getComputedStyle(tmpButton)
          // Firerox has a bug: styles.cssText always returns "". https://bugzilla.mozilla.org/show_bug.cgi?id=137687
          if (styles.cssText !== '') {
            listRoomsButtons.forEach(listRoomsButton => { listRoomsButton.style.cssText = styles.cssText })
          } else {
            const cssText = Object.values(styles).reduce(
              (css, propertyName) => `${css}${propertyName}:${styles.getPropertyValue(propertyName)};`
            )
            listRoomsButtons.forEach(listRoomsButton => { listRoomsButton.style.cssText = cssText })
          }
        }
      } catch (err) {
        console.error('[peertube-plugin-livechat] Failed applying styles on the «list rooms» button.', err)
      }

      listRoomsButtons.forEach(listRoomsButton => {
        if (listRoomsButton.classList.contains('peertube-plugin-livechat-prosody-list-rooms-btn-binded')) { return }
        listRoomsButton.classList.add('peertube-plugin-livechat-prosody-list-rooms-btn-binded')
        listRoomsButton.onclick = async (): Promise<void> => {
          console.log('[peertube-plugin-livechat] Opening the room list...')
          // TODO: use showModal (seems buggy with Peertube 3.2.1)

          try {
            document.querySelectorAll('.peertube-plugin-livechat-prosody-list-rooms-content')
              .forEach(dom => dom.remove())
            const container = document.createElement('div')
            container.classList.add('peertube-plugin-livechat-prosody-list-rooms-content')
            container.textContent = '...'
            listRoomsButton.after(container)

            const response = await fetch(getBaseRoute(clientOptions) + '/webchat/prosody-list-rooms', {
              method: 'GET',
              headers: peertubeHelpers.getAuthHeader()
            })
            if (!response.ok) {
              throw new Error('Response is not ok')
            }
            const settings = await peertubeHelpers.getSettings()
            const useChannelConfiguration = !(settings['disable-channel-configuration'])
            const json: ProsodyListRoomsResult = await response.json()
            if (!json.ok) {
              container.textContent = json.error
              container.classList.add('peertube-plugin-livechat-error')
            } else {
              const rooms = json.rooms.sort((a, b) => {
                const timestampA = a.lasttimestamp ?? 0
                const timestampB = b.lasttimestamp ?? 0
                if (timestampA === timestampB) {
                  return a.name.localeCompare(b.name)
                } else if (timestampA < timestampB) {
                  return 1
                } else {
                  return -1
                }
              })

              container.textContent = ''
              const table = document.createElement('table')
              table.classList.add('peertube-plugin-livechat-prosody-list-rooms')
              container.append(table)
              const labels: any = {
                RoomName: await peertubeHelpers.translate(LOC_ROOM_NAME),
                RoomDescription: await peertubeHelpers.translate(LOC_ROOM_DESCRIPTION),
                NotFound: await peertubeHelpers.translate(LOC_NOT_FOUND),
                Video: await peertubeHelpers.translate(LOC_VIDEO),
                Channel: await peertubeHelpers.translate(LOC_CHANNEL),
                LastActivity: await peertubeHelpers.translate(LOC_LAST_ACTIVITY),
                channelConfiguration: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_CHANNEL_TITLE)
              }

              const titleLineEl = document.createElement('tr')
              const titleNameEl = document.createElement('th')
              titleNameEl.textContent = labels.RoomName
              const titleDescriptionEl = document.createElement('th')
              titleDescriptionEl.textContent = labels.RoomDescription
              const titleVideoEl = document.createElement('th')
              titleVideoEl.textContent = `${labels.Video as string} / ${labels.Channel as string}`
              const titleLastActivityEl = document.createElement('th')
              titleLastActivityEl.textContent = labels.LastActivity
              titleLineEl.append(titleNameEl)
              titleLineEl.append(titleDescriptionEl)
              titleLineEl.append(titleVideoEl)
              titleLineEl.append(titleLastActivityEl)
              if (useChannelConfiguration) {
                const titleChannelConfiguration = document.createElement('th')
                titleChannelConfiguration.textContent = labels.channelConfiguration
                titleLineEl.append(titleChannelConfiguration)
              }
              titleLineEl.append(document.createElement('th'))
              table.append(titleLineEl)
              rooms.forEach(room => {
                const localpart = room.localpart
                const lineEl = document.createElement('tr')
                const nameEl = document.createElement('td')
                const aEl = document.createElement('a')
                aEl.textContent = room.name
                aEl.target = '_blank'
                const descriptionEl = document.createElement('td')
                descriptionEl.textContent = room.description
                const videoEl = document.createElement('td')
                const lastActivityEl = document.createElement('td')
                if (room.lasttimestamp && (typeof room.lasttimestamp === 'number')) {
                  const date = new Date(room.lasttimestamp * 1000)
                  lastActivityEl.textContent = date.toLocaleDateString() + ' ' + date.toLocaleTimeString()
                }
                const promoteButton = document.createElement('a')
                promoteButton.classList.add('primary-button', 'orange-button', 'peertube-button-link')
                promoteButton.style.margin = '5px'
                promoteButton.onclick = async () => {
                  await fetch(
                    getBaseRoute(clientOptions) + '/api/promote/' + encodeURIComponent(room.jid.replace(/@.*$/, '')),
                    {
                      method: 'PUT',
                      headers: peertubeHelpers.getAuthHeader()
                    }
                  )
                }
                // FIXME: we can use promoteSVG, which is in client scope...
                promoteButton.innerHTML = `<svg
                  xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 4.233 4.233"
                >
                  <g style="stroke-width:1.00021;stroke-miterlimit:4;stroke-dasharray:none">
                    <path
                    style="opacity:.998;fill:currentColor;fill-opacity:1;stroke:currentColor;stroke-width:1.17052;
                    stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                    d="M2.403.583V-.19a.94.94 0 0 1 .942-.943l1.962-.023 1.961.01a.94.94 0 0 1
                    .942.942v.772S6.586 4.9 5.307 4.92C4.027 4.939 2.403.583 2.403.583Z"
                    transform="matrix(.45208 0 0 .45208 -.526 1.335)"
                    />
                  </g>
                </svg>`
                const promoteEl = document.createElement('td')
                promoteEl.append(promoteButton)

                const channelConfigurationEl = document.createElement('td')
                nameEl.append(aEl)
                lineEl.append(nameEl)
                lineEl.append(descriptionEl)
                lineEl.append(videoEl)
                lineEl.append(lastActivityEl)
                if (useChannelConfiguration) {
                  lineEl.append(channelConfigurationEl) // else the element will just be dropped.
                }
                lineEl.append(promoteEl)
                table.append(lineEl)

                const writeChannelConfigurationLink = (channelId: number | string): void => {
                  const a = document.createElement('a')
                  a.href = '/p/livechat/configuration/channel?channelId=' + encodeURIComponent(channelId)
                  a.textContent = labels.channelConfiguration
                  channelConfigurationEl.append(a)
                }

                const channelMatches = localpart.match(/^channel\.(\d+)$/)
                if (channelMatches) {
                  // Here we have a channel chat room
                  // The backend should have added informations here
                  // (because the Peertube API can't work with channelId...)
                  const href = '/p/livechat/room?room=' + encodeURIComponent(localpart) + '&forcetype=1'
                  if (room.channel?.name) {
                    aEl.href = href // here we know that the channel still exists, so we can open the webchat.
                    const aVideoEl = document.createElement('a')
                    aVideoEl.textContent = room.channel?.displayName ?? '-'
                    aVideoEl.target = '_blank'
                    aVideoEl.href = '/video-channels/' + room.channel.name
                    videoEl.append(aVideoEl)
                  }
                  if (room.channel?.id) {
                    writeChannelConfigurationLink(room.channel.id)
                  }
                } else if (/^[a-zA-A0-9-]+$/.test(localpart)) {
                  // localpart must be a video uuid.
                  const uuid = localpart
                  const href = '/p/livechat/room?room=' + encodeURIComponent(uuid) + '&forcetype=1'
                  const p = fetch('/api/v1/videos/' + uuid, {
                    method: 'GET',
                    headers: peertubeHelpers.getAuthHeader()
                  })
                  p.then(async res => {
                    if (!res.ok) {
                      videoEl.textContent = labels.NotFound
                      return
                    }
                    const video: Video | undefined = await res.json()
                    if (!video) {
                      videoEl.textContent = labels.NotFound
                      return
                    }

                    aEl.href = href
                    const aVideoEl = document.createElement('a')
                    aVideoEl.textContent = video.name
                    aVideoEl.target = '_blank'
                    aVideoEl.href = '/videos/watch/' + uuid
                    videoEl.append(aVideoEl)
                    if (video.channel.id) {
                      writeChannelConfigurationLink(video.channel.id)
                    }
                  }, () => {
                    console.error('[peertube-plugin-livechat] Failed to retrieve video ' + uuid)
                  })
                }
              })
            }
          } catch (error: any) {
            console.error(error)
            peertubeHelpers.notifier.error(
              (error as Error).toString(),
              await peertubeHelpers.translate(LOC_LOADING_ERROR)
            )
          }
        }
      })
    }
  })
  registerSettingsScript({
    isSettingHidden: options => {
      const name = options.setting.name
      switch (name) {
        case 'prosody-c2s-port':
        case 'prosody-c2s-interfaces':
          return options.formValues['prosody-c2s'] !== true
        case 'prosody-s2s-port':
        case 'prosody-s2s-interfaces':
        case 'prosody-certificates-dir':
          return options.formValues['prosody-room-allow-s2s'] !== true
        case 'prosody-components-port':
        case 'prosody-components-interfaces':
        case 'prosody-components-list':
          return options.formValues['prosody-components'] !== true
        case 'converse-autocolors':
          return options.formValues['converse-theme'] !== 'peertube'
        case 'chat-per-live-video-warning':
          return !(options.formValues['chat-all-lives'] === true && options.formValues['chat-per-live-video'] === true)
        case 'auto-ban-anonymous-ip':
          return options.formValues['chat-no-anonymous'] !== false
        case 'prosody-firewall-configure-button':
          return options.formValues['prosody-firewall-enabled'] !== true
      }

      if (name?.startsWith('external-auth-')) {
        const m = name.match(/^external-auth-(\w+)-oidc-/)
        if (m) {
          return options.formValues['external-auth-' + m[1] + '-oidc'] !== true
        }
      }

      return false
    }
  })
}

export {
  register
}