ZO_CreateStringId("SI_BINDING_NAME_TOGGLE_CHATTER_MEMORY", "Toggle chatter memory")

TashDialogueLog = {}
TashDialogueLog.name = "TashDialogueLog"
TashDialogueLog.version = 1
TashDialogueLog.current_npc = nil
TashDialogueLog.current_dialogue = nil
TashDialogueLog.lastNPCTalked = nil
TashDialogueLog.constants = {
    IGNORE_DUPLICATES_SHOW_FIRST = 1,
    IGNORE_DUPLICATES_SHOW_LAST = 2,
    IGNORE_DUPLICATES_SHOW_ALL = 3,
    CHECK_CONVERSATION_DELAY = 200,
}
TashDialogueLog.Default = {
    settings = {
    },
    conversations = {
    },
    textValues = {},
    dialogues = {},
    duplicatesMode = TashDialogueLog.constants.IGNORE_DUPLICATES_SHOW_ALL,
}
        -- /script d(ZO_InteractWindowTargetAreaBodyText:GetText())
TashDialogueLog.ctrl = {
    ["TargetAreaTitle"]		= ZO_InteractWindowTargetAreaTitle,
    ["TargetAreaBodyText"]	= ZO_InteractWindowTargetAreaBodyText,
    ["PlayerAreaOptions"]	= ZO_InteractWindowPlayerAreaOptions,
    ["RewardArea"]			= ZO_InteractWindowRewardArea,
    ["RewardAreaHeader"]	= ZO_InteractWindowRewardAreaHeader,
    ["WindowTopBG"]			= ZO_InteractWindowTopBG,
    ["WindowBottomBG"]		= ZO_InteractWindowBottomBG,
    ["InteractWindow"]		= ZO_InteractWindow,
}

TashDialogueLog.chatterTypes = {
    [1] = CHATTER_START_BANK,
    [2] = CHATTER_START_GUILDBANK,
    [3] = CHATTER_START_KEEP,
    [4] = CHATTER_START_STABLE,
    [5] = CHATTER_START_SHOP,
    [6] = CHATTER_START_TRADINGHOUSE,
}


TashDialogueLog.colors = {
    NPCNAME = ZO_ColorDef:New("55AB80"),
    TIMESTAMP = ZO_CONTRAST_TEXT,
    BODYTEXT = ZO_WHITE,
    OPTIONTEXT = ZO_ColorDef:New("C5C29E"),
}


function TashDialogueLog:CheckForConversation()
    local isInConversation = GetUnitName("interact") ~= ""
    if isInConversation then
        zo_callLater(TashDialogueLog.CheckForConversation, TashDialogueLog.constants.CHECK_CONVERSATION_DELAY)
    else
        TashDialogueLog:OnCloseChatter()
    end
end


function TashDialogueLog:FormatTimestamp(timestamp)
    return ZO_FormatDurationAgo(GetTimeStamp() - timestamp)
end


function TashDialogueLog:FindExistingPhrase(NPC, phrase)
    local existingPhrases = TashDialogueLog.savedVariables.dialogues[NPC]
    if existingPhrases == nil then return nil end
    for i=1, #existingPhrases do
        local existingPhrase = existingPhrases[i]
        if existingPhrase.bodyTextHash == phrase.bodyTextHash and existingPhrase.optionTextHash == phrase.optionTextHash then
            return existingPhrase
        end
    end
end


function TashDialogueLog:ConvertOldPhrases()
    local dialogues_old = TashDialogueLog.savedVariables.dialogues
    TashDialogueLog.savedVariables.dialogues = {}

    for NPCName, data in pairs(dialogues_old) do
        local phrases = data.phrases
        for i=1, #phrases do
            local phrase = phrases[i]
            TashDialogueLog:AddPhraseAsHashes(phrase.timestamp, NPCName, phrase.bodyTextHash, phrase.optionTextHash)
        end
    end
end


function TashDialogueLog:AddPhraseAsHashes(timestamp, NPCName, bodyTextHash, optionTextHash)
    if TashDialogueLog.savedVariables.dialogues[NPCName] == nil then
        TashDialogueLog.savedVariables.dialogues[NPCName] = {}
    end

    local npcDialogues = TashDialogueLog.savedVariables.dialogues[NPCName]
    local phrase = {bodyTextHash=bodyTextHash, optionTextHash=optionTextHash}
    local existingPhrase = TashDialogueLog:FindExistingPhrase(NPCName, phrase)

    if existingPhrase == nil then
        existingPhrase = {
            bodyTextHash=bodyTextHash, optionTextHash=optionTextHash, timestamps={}
        }
        npcDialogues[#npcDialogues+1] = existingPhrase
    end
    table.insert(existingPhrase.timestamps, timestamp)

    TashDialogueLog.interface:OnPhraseAdded()
end


function TashDialogueLog:AddPhrase(timestamp, NPCName, bodyText, optionText)
    local bodyTextHash = TashDialogueLog:AddTextValue(bodyText)
    local optionTextHash = TashDialogueLog:AddTextValue(optionText)
    TashDialogueLog:AddPhraseAsHashes(timestamp, NPCName, bodyTextHash, optionTextHash)
end


function TashDialogueLog:BuildPhrasesTable(filter, ignoreDuplicates)
    local result = {}
    local textValues = TashDialogueLog.savedVariables.textValues
    for NPCName, phrases in pairs(TashDialogueLog.savedVariables.dialogues) do
        for i=1, #phrases do
            local phrase = phrases[i]
            -- d(phrase)
            local bodyText = nil
            local optionText = nil
            if phrase.bodyTextHash ~= nil then bodyText = textValues[phrase.bodyTextHash] end
            if phrase.optionTextHash ~= nil then optionText = textValues[phrase.optionTextHash] end
            local timestamps = phrase.timestamps
            if ignoreDuplicates == TashDialogueLog.constants.IGNORE_DUPLICATES_SHOW_FIRST then
                timestamps = { timestamps[1] }
            elseif ignoreDuplicates == TashDialogueLog.constants.IGNORE_DUPLICATES_SHOW_LAST then
                timestamps = { timestamps[#timestamps] }
            end
            for n=1, #timestamps do
                local data = {}
                data.NPC = NPCName
                data.bodyText = bodyText
                data.optionText = optionText
                data.timestamp = timestamps[n]
                -- d(data)
                local filtered = true
                if filter ~= nil then filtered = filter(data) end
                if filtered then result[#result+1] = data end
            end
        end
    end
    return result
end

function TashDialogueLog:AddTextValue(text)
    if text == nil or text == "" then
        return nil
    end
    local hash = tostring(HashString(text))
    TashDialogueLog.savedVariables.textValues[hash] = text
    return hash
end


function TashDialogueLog:OnCloseChatter()
    TashDialogueLog.lastOptionClicked = nil
    -- d("Conversation ended")
end


function TashDialogueLog:OnChatterOptionClicked(label)
    TashDialogueLog.lastOptionClicked = {
        text = label:GetText(),
        type_ = label.optionType,
    }
end


function TashDialogueLog:OnConversation(...)
    local timestamp = GetTimeStamp()
    local bodyText = TashDialogueLog.ctrl.TargetAreaBodyText:GetText()
    local npcName = GetUnitName("interact")
    local optionText = nil
    if TashDialogueLog.lastOptionClicked ~= nil then
        optionText = TashDialogueLog.lastOptionClicked.text
    end
    TashDialogueLog:AddPhrase(timestamp, npcName, bodyText, optionText)
    TashDialogueLog:CheckForConversation()
end


-- Initialization routines
function TashDialogueLog:Initialize()
    TashDialogueLog.savedVariables = ZO_SavedVars:New(
        "TashDialogueLogVars", TashDialogueLog.version, nil, TashDialogueLog.Default
    )
    EVENT_MANAGER:RegisterForEvent(
        TashDialogueLog.name, EVENT_CONVERSATION_UPDATED, TashDialogueLog.OnConversation
    )
    EVENT_MANAGER:RegisterForEvent(
        TashDialogueLog.name, EVENT_CHATTER_BEGIN, TashDialogueLog.OnConversation
    )
    EVENT_MANAGER:RegisterForEvent(
        TashDialogueLog.name, EVENT_QUEST_OFFERED, TashDialogueLog.OnConversation
    )
    EVENT_MANAGER:RegisterForEvent(
        TashDialogueLog.name, EVENT_QUEST_COMPLETE_DIALOG, TashDialogueLog.OnConversation
    )

    TashDialogueLog.interface = TashDLInterface
    TashDialogueLog.interface.Initialize()
    SLASH_COMMANDS["/conversations"] = function() TashDialogueLog.interface.mainWindow:Toggle() end
end

function TashDialogueLog.OnAddOnLoaded(event, addonName)
    -- The event fires each time *any* addon loads - but we only care about when our own addon loads.
    if addonName == TashDialogueLog.name then
        TashDialogueLog:Initialize()
    end
end

EVENT_MANAGER:RegisterForEvent(TashDialogueLog.name, EVENT_ADD_ON_LOADED, TashDialogueLog.OnAddOnLoaded)