const simpleGet = require('simple-get')

const store = {
  urls: [],
  checkIntervalSeconds: null,
  alreadyAdded: new Set(),
  alreadyRemoved: new Set(),
  timeout: null
}

async function register ({
  settingsManager,
  storageManager,
  peertubeHelpers,
  registerSetting
}) {
  const { logger } = peertubeHelpers

  registerSetting({
    name: 'blocklist-urls',
    label: 'Blocklist URLs (one per line)',
    type: 'input-textarea',
    private: true
  })

  registerSetting({
    name: 'check-seconds-interval',
    label: 'Blocklist check frequency (seconds)',
    type: 'input',
    private: true,
    default: 3600 // 1 Hour
  })

  const settings = await settingsManager.getSettings([ 'check-seconds-interval', 'blocklist-urls' ])

  await load(peertubeHelpers, storageManager, settings['blocklist-urls'], settings['check-seconds-interval'])

  settingsManager.onSettingsChange(settings => {
    load(peertubeHelpers, storageManager, settings['blocklist-urls'], settings['check-seconds-interval'])
      .catch(err => logger.error('Cannot load auto block videos plugin.', { err }))
  })
}

async function unregister () {
  return
}

module.exports = {
  register,
  unregister
}

// ############################################################################

async function load (peertubeHelpers, storageManager, blocklistUrls, checkIntervalSeconds) {
  const { logger } = peertubeHelpers

  if (store.timeout) clearTimeout(store.timeout)

  store.checkIntervalSeconds = checkIntervalSeconds

  store.urls = (blocklistUrls || '').split('\n')
                                    .filter(url => !!url)

  if (store.urls.length === 0) {
    logger.info('Do not load auto block videos plugin because of empty blocklist URLs.')
    return
  }

  logger.info('Loaded %d blocklist URLs for auto block videos plugin.', store.urls.length, { urls: store.urls })

  runLater(peertubeHelpers, storageManager)
}

async function runCheck (peertubeHelpers, storageManager) {
  const { logger } = peertubeHelpers

  if (store.urls.length === 0) return runLater(peertubeHelpers, storageManager)

  let lastChecks = await storageManager.getData('last-checks')
  if (!lastChecks) lastChecks = {}

  const newLastCheck = {}

  for (const url of store.urls) {
    try {
      const { data } = await get(url)
      newLastCheck[url] = new Date().toISOString()

      const lastCheckTime = lastChecks[url]
        ? new Date(lastChecks[url]).getTime()
        : 0

      if (Array.isArray(data.data) === false) {
        logger.error('JSON response is not valid from %s.', { data })
        continue
      }

      for (const entity of data.data) {
        if (!entity.value) {
          logger.error('JSON entity is not valid.', { entity })
          continue
        }

        // We already checked this entity?
        if (entity.updatedAt) {
          const updatedAtTime = new Date(entity.updatedAt).getTime()

          if (updatedAtTime < lastCheckTime) continue
        }

        if (entity.action === 'remove') await removeEntity(peertubeHelpers, entity.value)
        else await addEntity(peertubeHelpers, entity.value)
      }
    } catch (err) {
      logger.warn('Cannot auto block videos from %s.', url, { err })
    }
  }

  await storageManager.storeData('last-checks', newLastCheck)

  runLater(peertubeHelpers, storageManager)
}

function runLater (peertubeHelpers, storageManager) {
  const { logger } = peertubeHelpers

  logger.debug('Will run auto videos block check in %d seconds.', store.checkIntervalSeconds)

  store.timeout = setTimeout(() => {
    runCheck(peertubeHelpers, storageManager)
  }, store.checkIntervalSeconds * 1000)
}

function get (url) {
  return new Promise((resolve, reject) => {
    simpleGet.concat({ url, method: 'GET', json: true }, function (err, res, data) {
      if (err) return reject(err)

      return resolve({ res, data })
    })
  })
}

async function addEntity (peertubeHelpers, value) {
  const { moderation, videos, logger } = peertubeHelpers

  if (store.alreadyAdded.has(value)) return

  store.alreadyRemoved.delete(value)
  store.alreadyAdded.add(value)

  const video = await videos.loadByUrl(value)
  if (!video) return

  if (video.remote !== true) {
    logger.info('Do not auto block our own video %s.', value)
    return
  }

  logger.info('Auto block video %s from blocklist.', value)

  const reason = 'Automatically blocked from auto block plugin.'
  return moderation.blacklistVideo({ videoIdOrUUID: video.id, createOptions: { reason } })
}

async function removeEntity (peertubeHelpers, value) {
  const { moderation, logger, videos } = peertubeHelpers

  if (store.alreadyRemoved.has(value)) return

  store.alreadyAdded.delete(value)
  store.alreadyRemoved.add(value)

  const video = await videos.loadByUrl(value)
  if (!video) return

  logger.info('Auto removing video %s from blocklist.', value)

  return moderation.unblacklistVideo({ videoIdOrUUID: video.id })
}