interface ContentData {
  contentId: string
  userId: string
  [key: string]: any
}

interface Cache {
  [key: string]: ContentData[]
}

declare global {
  interface Window {
    DEBUG_EDIT_FIELD_UPDATE_CACHE: boolean
  }
}

export default (function () {
  let cache: Cache = {}
  let puts = 0
  let gets = 0
  let hits = 0

  function log(...args: any[]) {
    if (
      !window.DEBUG_EDIT_FIELD_UPDATE_CACHE ||
      typeof console === 'undefined'
    ) {
      return
    }

    const newArguments = Array.prototype.slice.call(args, 0)
    newArguments[0] = '[EditFieldUpdateCache] ' + newArguments[0]
    newArguments.push('puts', puts)
    newArguments.push('gets', gets)
    newArguments.push('hits', hits)
    newArguments.push(
      (gets === 0 || hits === 0
        ? 0.0
        : (gets === 0 ? 1.0 : hits === 0 ? 0.0 : hits / gets) * 100) + '%',
    )
    newArguments.push('entries', Object.keys(cache).length)

    console.log(...newArguments)
  }

  return {
    init: function (key: string) {
      if (!cache[key]) {
        cache[key] = []
        log('%cinit', 'color: blue', key)
      }
    },

    put: function (data: ContentData) {
      if (!data) {
        return
      }

      const contentId = data.contentId
      if (!contentId) {
        return
      }

      if (cache[contentId]) {
        puts += 1
        log('%cput', 'color: blue', contentId)

        const userId = data.userId
        let contentData = cache[contentId]
        let userDataIndex: number | undefined = undefined

        if (!contentData) {
          contentData = []
          cache[contentId] = contentData
        }

        let index = 0
        for (const content of contentData) {
          if (content.userId === userId) {
            userDataIndex = index
            break
          }
          index++
        }

        if (userDataIndex !== undefined && userDataIndex >= 0) {
          contentData.splice(userDataIndex, 1, data)
        } else {
          contentData.push(data)
        }
      } else {
        log('%cput (skipped)', 'color: blue', contentId)
      }
    },

    get: function (contentId: string): ContentData[] {
      gets += 1
      const contentData = cache[contentId]

      if (contentData) {
        hits += 1
        log('%cget (hit)', 'color: green', contentId)
      } else {
        log('%cget (miss)', 'color: red', contentId)
      }

      return contentData
    },

    invalidate: function (contentIds: string[]) {
      if (contentIds.length < 1) {
        return
      }

      // clean out unused cache entries before making call to restore
      const cleanCache: Cache = {}

      contentIds.forEach(function (contentId) {
        const contentData = cache[contentId]
        if (contentData) {
          cleanCache[contentId] = contentData
        }
      })

      cache = cleanCache
      log('%cinvalidate', 'color: blue', 'keep: ' + contentIds)
    },
  }
})()
