Librarian = {}
Librarian.defaults = {books = {}}

ZO_CreateStringId("SI_BINDING_NAME_TOGGLE_LIBRARIAN", "Toggle Librarian")
ZO_CreateStringId("SI_BINDING_NAME_RELOAD_UI", "Reload UI")
ZO_CreateStringId("SI_WINDOW_TITLE_LIBRARIAN", "Librarian")
ZO_CreateStringId("SI_LIBRARIAN_SORT_TYPE_UNREAD", "Unread")
ZO_CreateStringId("SI_LIBRARIAN_SORT_TYPE_FOUND", "Found")
ZO_CreateStringId("SI_LIBRARIAN_SORT_TYPE_TITLE", "Title")
ZO_CreateStringId("SI_LIBRARIAN_SORT_TYPE_WORD_COUNT", "Words")
ZO_CreateStringId("SI_LIBRARIAN_MARK_UNREAD", "Mark as Unread")
ZO_CreateStringId("SI_LIBRARIAN_MARK_READ", "Mark as Read")

local SORT_ARROW_UP = "EsoUI/Art/Miscellaneous/list_sortUp.dds"
local SORT_ARROW_DOWN = "EsoUI/Art/Miscellaneous/list_sortDown.dds"

local previousBook
local scrollChild
local sortField = "Found"
local sortAscending = false

function Librarian:Initialise()
 	scrollChild = LibrarianFrameScrollContainer:GetNamedChild("ScrollChild")
 	scrollChild:SetAnchor(TOPRIGHT, nil, TOPRIGHT, -5, 0)
	self.savedVars = ZO_SavedVars:New("Librarian_SavedVariables", 1, nil, self.defaults, nil)

	self:SortBooks()

	self:InitializeKeybindStripDescriptors()
	self:InitializeScene()
end

function Librarian:InitializeKeybindStripDescriptors()
    self.keybindStripDescriptor =
    {
        {
            alignment = KEYBIND_STRIP_ALIGN_RIGHT,
            name = GetString(SI_LORE_LIBRARY_READ),
            keybind = "UI_SHORTCUT_PRIMARY",
            callback = function()
                self:ReadBook(self.mouseOverRow.id)
            end,
        },
        {
            alignment = KEYBIND_STRIP_ALIGN_RIGHT,
            name = function()
            	if not self.mouseOverRow then return nil end
            	if self.savedVars.books[self.mouseOverRow.id].unread then
            		return GetString(SI_LIBRARIAN_MARK_READ)
            	else
            		return GetString(SI_LIBRARIAN_MARK_UNREAD)
            	end
            end,
            keybind = "UI_SHORTCUT_SECONDARY",
            visible = function()
            	return self.mouseOverRow
            end,
            callback = function()
            	local book = self.savedVars.books[self.mouseOverRow.id]
                book.unread = not book.unread
                if book.unread then self.mouseOverRow.unread:SetAlpha(1) else self.mouseOverRow.unread:SetAlpha(0) end
                KEYBIND_STRIP:RemoveKeybindButtonGroup(self.keybindStripDescriptor)
                KEYBIND_STRIP:AddKeybindButtonGroup(self.keybindStripDescriptor)
            end,
        }
    }
end

function Librarian:InitializeScene()
	if not LIBRARIAN_SCENE then
		LIBRARIAN_TITLE_FRAGMENT = ZO_SetTitleFragment:New(SI_WINDOW_TITLE_LIBRARIAN)
		LIBRARIAN_SCENE = ZO_Scene:New("librarian", SCENE_MANAGER)
		LIBRARIAN_SCENE:AddFragmentGroup(FRAGMENT_GROUP.UI_WINDOW)
		LIBRARIAN_SCENE:AddFragmentGroup(FRAGMENT_GROUP.FRAME_TARGET_STANDARD_RIGHT_PANEL)
		LIBRARIAN_SCENE:AddFragment(ZO_FadeSceneFragment:New(LibrarianFrame))
		LIBRARIAN_SCENE:AddFragment(RIGHT_BG_FRAGMENT)
		LIBRARIAN_SCENE:AddFragment(TITLE_FRAGMENT)
		LIBRARIAN_SCENE:AddFragment(LIBRARIAN_TITLE_FRAGMENT)
		LIBRARIAN_SCENE:AddFragment(EXPERIENCE_BAR_FRAGMENT)
		LIBRARIAN_SCENE:AddFragment(CODEX_WINDOW_SOUNDS)
	end
end

function Librarian:StoreBook(title, body, medium, showTitle)
	if not self:FindBook(title) then
		self:AddBook(title, body, medium, showTitle)
	end
end

function Librarian:FindBook(title)
	for i, book in ipairs(self.savedVars.books) do
		if book.title == title then return book end
	end
end

function Librarian:AddBook(title, body, medium, showTitle)
	local book = {title = title, body = body, medium = medium, showTitle = showTitle, timeStamp = GetTimeStamp(), unread = true}
	table.insert(self.savedVars.books, book)
	self:SortBooks()
	d("Book added to Librarian.")
	--ZO_CenterScreenAnnounce_GetAnnounceObject():AddMessage(EVENT_SKILL_RANK_UPDATE, CSA_EVENT_LARGE_TEXT, SOUNDS.SKILL_LINE_LEVELED_UP, "Test")
end

function Librarian:Toggle()
	if LibrarianFrame:IsControlHidden() then
		SCENE_MANAGER:Show("librarian")
	else
		SCENE_MANAGER:Hide("librarian")
	end
end

function Librarian:LayoutBooks()
    ZO_Scroll_ResetToTop(LibrarianFrameScrollContainer)
    previousBook = nil
    for i, book in ipairs(self.savedVars.books) do
		self:LayoutBook(i, book)
    end
end

function Librarian:LayoutBook(i, book)
	local bookControl = GetControl("LibrarianBook"..i)
	if not bookControl then
		bookControl = CreateControlFromVirtual("LibrarianBook", scrollChild, "LibrarianBook", i)
		bookControl.id = i
	end

	bookControl.unread = bookControl:GetNamedChild("Unread")
	bookControl.found = bookControl:GetNamedChild("Found")
	bookControl.title = bookControl:GetNamedChild("Title")
	bookControl.wordCount = bookControl:GetNamedChild("WordCount")

	if book.unread then bookControl.unread:SetAlpha(1) else bookControl.unread:SetAlpha(0) end
	bookControl.found:SetText(self:FormatClockTime(book.timeStamp))
	bookControl.title:SetText(book.title)
	if not book.wordCount then
		local wordCount = 0
		for w in book.body:gmatch("%S+") do wordCount = wordCount + 1 end
		book.wordCount = wordCount
	end
	bookControl.wordCount:SetText(book.wordCount)

	if not previousBook then
    	bookControl:SetAnchor(TOPLEFT, scrollChild, TOPLEFT)
    else
    	bookControl:SetAnchor(TOPLEFT, previousBook, BOTTOMLEFT)
    end
    previousBook = bookControl
end

function Librarian:InitialiseSortHeader(control, name, tag)
	control.tag = tag
	local nameControl = GetControl(control, "Name")
    nameControl:SetFont("ZoFontHeader")
    nameControl:SetText(GetString(name))
    nameControl:SetHorizontalAlignment(alignment or TEXT_ALIGN_LEFT)
    control.initialDirection = initialDirection or ZO_SORT_ORDER_DOWN
    control.usesArrow = true
end

function Librarian:SortBy(control)
	local field = control.tag
	if field == sortField then
		sortAscending = not sortAscending
	else
		sortField = field
		sortAscending = true
	end

	self:SortBooks()
end

function Librarian:SortBooks()
	local control

	if sortField == "Unread" then
		control = LibrarianFrameSortByUnread
		if sortAscending then
			table.sort(self.savedVars.books, function(a, b) return a.unread and not b.unread end)
		else
			table.sort(self.savedVars.books, function(a, b) return not a.unread and b.unread end)
		end
	elseif sortField == "Found" then
		control = LibrarianFrameSortByTime
		if sortAscending then
			table.sort(self.savedVars.books, function(a, b) return a.timeStamp < b.timeStamp end)
		else
			table.sort(self.savedVars.books, function(a, b) return a.timeStamp > b.timeStamp end)
		end
	elseif sortField == "Title" then
		control = LibrarianFrameSortByTitle
		if sortAscending then
			table.sort(self.savedVars.books, function(a, b) return a.title < b.title end)
		else
			table.sort(self.savedVars.books, function(a, b) return a.title > b.title end)
		end
	elseif sortField == "WordCount" then
		control = LibrarianFrameSortByWordCount
		if sortAscending then
			table.sort(self.savedVars.books, function(a, b) return a.wordCount < b.wordCount end)
		else
			table.sort(self.savedVars.books, function(a, b) return a.wordCount > b.wordCount end)
		end
	end

	LibrarianFrameSortByUnread:GetNamedChild("Arrow"):SetHidden(true)
	LibrarianFrameSortByTime:GetNamedChild("Arrow"):SetHidden(true)
	LibrarianFrameSortByTitle:GetNamedChild("Arrow"):SetHidden(true)

	local arrow = control:GetNamedChild("Arrow")
	if sortAscending then
		arrow:SetTexture(SORT_ARROW_DOWN)
	else
		arrow:SetTexture(SORT_ARROW_UP)
	end
	arrow:SetHidden(false)

	self:LayoutBooks()
end

function Librarian:ReadBook(id)
	local book = self.savedVars.books[id]
	LORE_READER:SetupBook(book.title, book.body, book.medium, book.showTitle)
	LORE_READER.returnScene = "librarian"
    SCENE_MANAGER:Show("loreReaderInteraction")
    PlaySound(LORE_READER.OpenSound)
end

function Librarian:OnMouseEnter(buttonPart)
	self.mouseOverRow = buttonPart
	local highlight = buttonPart:GetNamedChild("Highlight")
	if highlight then
		if not highlight.animation then
	        highlight.animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("ShowOnMouseOverLabelAnimation", highlight)
	    end
    	highlight.animation:PlayForward()
    end

    KEYBIND_STRIP:AddKeybindButtonGroup(self.keybindStripDescriptor)
end

function Librarian:OnMouseExit(buttonPart)
	self.mouseOverRow = nil
	local highlight = buttonPart:GetNamedChild("Highlight")
	if highlight and highlight.animation then
        highlight.animation:PlayBackward()
    end

    KEYBIND_STRIP:RemoveKeybindButtonGroup(self.keybindStripDescriptor)
end

function Librarian:FormatClockTime(time)
    if(CLOCK_FORMAT == nil) then
        CLOCK_FORMAT = (GetCVar("Language.2") == "en") and TIME_FORMAT_PRECISION_TWELVE_HOUR or TIME_FORMAT_PRECISION_TWENTY_FOUR_HOUR
    end

    local midnightSeconds = GetSecondsSinceMidnight()
    local utcSeconds = GetTimeStamp() % 86400
    local offset = midnightSeconds - utcSeconds
    if offset < -43200 then
    	offset = offset + 86400
    end

    local dateString = GetDateStringFromTimestamp(time)
    local timeString = ZO_FormatTime(time + offset, TIME_FORMAT_STYLE_CLOCK_TIME, CLOCK_FORMAT)
	return string.format("%s %s", dateString, timeString)
end

local function SlashCommand(args)
	Librarian:Toggle()
end

local function OnAddonLoaded(event, addon)
	if addon == "Librarian" then
		Librarian:Initialise()
	end
end

local function OnShowBook(eventCode, title, body, medium, showTitle)
	Librarian:StoreBook(title, body, medium, showTitle)
end

SLASH_COMMANDS["/librarian"] = SlashCommand

EVENT_MANAGER:RegisterForEvent("Librarian", EVENT_ADD_ON_LOADED, OnAddonLoaded)
EVENT_MANAGER:RegisterForEvent("Librarian", EVENT_SHOW_BOOK, OnShowBook)