-- Copyright © 2018 Daniel Pittman <daniel@rimspace.net>
-- See LICENSE for more details.
if not SlippyCheezeReadItOnce then
      SlippyCheezeReadItOnce = {
         ADDON_NAME="SlippyCheezeReadItOnce",
         DISPLAY_NAME = "|c798BD2ReadItOnce|r",
         DOUBLE_TAP_TIME = 1000,
         previousBook = {id=nil, time=0},
         -- seen holds our saved variables.
         seen = {}
      }
end

-- my local alias for the addon itself.
local M = SlippyCheezeReadItOnce

local unpack = table.unpack or unpack
local insert = table.insert

local function msg(msg, ...)
   local args = {}
   for n=1, select('#', ...) do
      insert(args, tostring(select(n, ...)))
   end

   d(DISPLAY_NAME..": "..zo_strformat(msg, unpack(args)))
end

-- return bool, have we seen this before.  never called before saved variables
-- are loaded and initialized.
function M:HaveSeenBookBefore(self, id, title, body)
   if type(id) ~= "number" then
      msg("ReadItOnce: id is <<1>> (<<2>>)", type(id), id)
      return false
   end

   -- ensure that we index by string, not number, in the table.
   local id = tostring(id)
   local bodyHash = HashString(body)

   local record = self.seen[id]
   if record then
      -- probably have seen it before, but check for changes
      if record.id ~= id then
         d("ReadItOnce: book id changed from <<1>> to <<2>>", record.id, id)
      end
      if record.title ~= title then
         d("ReadItOnce: book title changed from '<<1>>' to '<<2>>'", record.title, title)
      end
      if record.bodyHash ~= bodyHash then
         d("ReadItOnce: book body changed")
      end

      -- don't show.
      return true
   end

   -- have not seen, record it, and return that fact
   self.seen[id] = {id=id, title=title, bodyHash=bodyHash}
   return false
end

-- Called when we want to skip showing a book.  Probably going to be very
-- strange if you call it any other time!
function M:DoNotShowThisBook(self)
   PlaySound(SOUNDS.NEGATIVE_CLICK)

   -- local msg = zo_strformat("<<1>>: You have already read \"<<2>>\"", DISPLAY_NAME, title)
   local msg = zo_strformat("You have already read \"<<1>>\"", title)

   -- ZO_AlertNoSuppression(UI_ALERT_CATEGORY_ALERT, nil, )

   local params = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_SMALL_TEXT, nil)
   params:SetText(msg)
   params:SetCSAType(CENTER_SCREEN_ANNOUNCE_TYPE_LORE_BOOK_LEARNED)
   params:SetLifespanMS(850)
   CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(params)

   EndInteraction(INTERACTION_BOOK)
end

-- Sadly, we have to override the original method, which is a local anonymous
-- function, and which we have apparently no access to in order to hook nicely.
--
-- The bulk of this is a direct copy-paste from the lore reader, as of USOUI
-- 100023
--
-- The HaveSeenBook logic is my addition.
function M:OnShowBookOverride(eventCode, title, body, medium, showTitle, bookId)
   local do_not_show = false

   -- never block a book if we are not in the most basic state, which is the
   -- world interaction state.
   if SCENE_MANAGER:IsShowingBaseScene() then
      -- handle the case of double-activation to bypass the restriction.
      local now = GetGameTimeMilliseconds()
      if previousBook.id == bookId then
         if (now - previousBook.time) > DOUBLE_TAP_TIME then
            do_not_show = true
         end
      else
         previousBook.id = bookId
      end
      -- msg("force_show <<1>> now <<2>> prev.time <<3>> deltaT <<4>> prev.id <<5>> id <<6>>",
      --      force_show, now, previousBook.time, now - previousBook.time, previousBook.id, id)
      previousBook.time = now
   else -- not in the base scene
      do_not_show = true
   end

   -- implement the block, if appropriate.
   if HaveSeenBookBefore(bookId, title, body) and not force_show then
   end

   -- meh, this is copied from the local function in the ZOS code. :(
   if LORE_READER:Show(title, body, medium, showTitle) then
      PlaySound(LORE_READER.OpenSound)
   else
      EndInteraction(INTERACTION_BOOK)
   end
end

local function ScanKnowLoreBooks()
end

local function OnAddonLoaded(_, name)
   if name ~= ADDON_NAME then return end
   EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED)

   -- if the second argument, the version, changes then the data is wiped and
   -- replaced with the defaults.
   seen = ZO_SavedVars:NewAccountWide("SlippyCheezeReadItOnceData", 1)

   -- replace the original event handler with ours; sadly, we don't have
   -- access to the original implementation to do anything nicer. :/
   LORE_READER.control:UnregisterForEvent(EVENT_SHOW_BOOK)
   LORE_READER.control:RegisterForEvent(EVENT_SHOW_BOOK, OnShowBookOverride)
end

-- bootstrapping
EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED, OnAddonLoaded)