local CRAFTING_RESULTS_TEMPLATE = "ZO_CraftingResultItem"

ZO_CraftingResults_Keyboard = ZO_CraftingResults_Base:Subclass()

local MAX_RUNE_ROWS = 3
local function RegisterEnchantDialog(dialogName, control)
    local function SetupEnchantDialog(dialog)
        local numTranslation = GetNumLastCraftingResultLearnedTranslations()
        for i = 1, numTranslation do
            local translationName, itemName, icon, _, _, _, _, displayQuality = GetLastCraftingResultLearnedTranslationInfo(i)

            local row = control:GetNamedChild("Row" .. i)
            row:SetHidden(false)

            row.icon:SetTexture(icon)

            row.itemName:SetText(zo_strformat(SI_TOOLTIP_ITEM_NAME, itemName))
            local r, g, b = GetInterfaceColor(INTERFACE_COLOR_TYPE_ITEM_QUALITY_COLORS, displayQuality)
            row.itemName:SetColor(r, g, b, 1)

            row.translatedName:SetText(translationName)
        end

        for i = numTranslation + 1, MAX_RUNE_ROWS do
            control:GetNamedChild("Row" .. i):SetHidden(true)
        end
    end

    ZO_Dialogs_RegisterCustomDialog(dialogName,
    {
        customControl = control,
        setup = SetupEnchantDialog,
        title =
        {
            text = SI_ENCHANTING_TRANSLATION_LEARNED_DIALOG_TITLE,
        },
        buttons =
        {
            {
                keybind = "DIALOG_NEGATIVE",
                control = control:GetNamedChild("Exit"),
                text = SI_EXIT_BUTTON,
            },
        }
    })
end

local MAX_ALCHEMY_ROWS = 3
local MAX_ITEM_TRAITS = 4

local function SetDefaultOptionValue(options, optionName, defaultValue)
    if options[optionName] == nil then
        options[optionName] = defaultValue
    end
end

-- The options parameter is a table that can contain any of the following values:
--  colorItemName:  Whether to apply the quality color for the reagent name label (defaults to true)
--  centerAlignTraits:  Whether to center-align traits relative to reagent label (defaults to true)
--  rowSpacing:  The amount of spacing between reagent rows (defaults to 40)
function ZO_CraftingResults_SetupAlchemyDialogLayout(control, options)
    -- Set default values for options
    if not options then
        options = {}
    end

    SetDefaultOptionValue(options, "colorItemName", true)
    SetDefaultOptionValue(options, "centerAlignTraits", true)
    SetDefaultOptionValue(options, "rowSpacing", 40)

    local numLearnedTraits = GetNumLastCraftingResultLearnedTraits()
    local itemNameToRow = {}
    local currentRowIndex = 1

    for i = 1, numLearnedTraits do
        local traitName, itemName, icon, sellPrice, meetsUsageRequirement, equipType, itemStyle, displayQuality = GetLastCraftingResultLearnedTraitInfo(i)

        if not itemNameToRow[itemName] then
            local row = control:GetNamedChild("Row" .. currentRowIndex)
            currentRowIndex = currentRowIndex + 1

            itemNameToRow[itemName] = row

            row:SetHidden(false)

            row.icon:SetTexture(icon)

            row.itemName:SetText(zo_strformat(SI_TOOLTIP_ITEM_NAME, itemName))

            if options.colorItemName then
                local r, g, b = GetInterfaceColor(INTERFACE_COLOR_TYPE_ITEM_QUALITY_COLORS, displayQuality)
                row.itemName:SetColor(r, g, b, 1)
            end

            row.containerHeight = 0

            for traitIndex = 2, MAX_ITEM_TRAITS do
                row.traits[traitIndex]:SetHidden(true)
            end

            row.currentTraitIndex = 1
        end

        local row = itemNameToRow[itemName]

        local currentTraitIndex = row.currentTraitIndex
        row.traits[currentTraitIndex]:SetText(zo_strformat(SI_ALCHEMY_REAGENT_TRAIT_FORMATTER, traitName))
        row.traits[currentTraitIndex]:SetHidden(false)

        row.currentTraitIndex = currentTraitIndex + 1
        row.containerHeight = row.containerHeight + select(2, row.traits[currentTraitIndex]:GetTextDimensions())
    end

    for i = currentRowIndex, MAX_ALCHEMY_ROWS do
        control:GetNamedChild("Row" .. i):SetHidden(true)
    end

    local prevRow
    for i = 1, currentRowIndex - 1 do
        local row = control:GetNamedChild("Row" .. i)
        row.traitContainer:SetHeight(row.containerHeight)
        local currentOffset = zo_max(row.containerHeight - row:GetHeight(), 0) * .5 + 10

        if i == 1 then
            if options.centerAlignTraits then
                row:SetAnchor(TOP, control:GetNamedChild("Description"), BOTTOM, 0, currentOffset)
            else
                currentOffset = 60
                row:SetAnchor(TOPLEFT, control:GetNamedChild("Description"), BOTTOMLEFT, 0, currentOffset)
            end
        else
            local totalOffset

            if options.centerAlignTraits then
                local prevOffset = zo_max(prevRow.containerHeight - prevRow:GetHeight(), 0) * .5 + 10
                totalOffset = prevOffset + currentOffset
            else
                totalOffset = prevRow.containerHeight + options.rowSpacing
            end

            row:SetAnchor(TOP, prevRow, BOTTOM, 0, totalOffset)
        end

        prevRow = row
    end

    if not options.centerAlignTraits then
        control:GetNamedChild("Exit"):SetAnchor(TOPLEFT, prevRow, BOTTOMLEFT, 0, prevRow.containerHeight + options.rowSpacing)
    end
end

local function RegisterAlchemyDialog(dialogName, control, options)
    local function SetupAlchemyDialog(dialog)
        ZO_CraftingResults_SetupAlchemyDialogLayout(control, options)
    end

    ZO_Dialogs_RegisterCustomDialog(dialogName,
    {
        customControl = control,
        setup = SetupAlchemyDialog,
        title =
        {
            text = SI_ALCHEMY_REAGENT_TRAIT_LEARNED_DIALOG_TITLE,
        },
        buttons =
        {
            {
                keybind = "DIALOG_NEGATIVE",
                control = control:GetNamedChild("Exit"),
                text = SI_EXIT_BUTTON,
            },
        }
    })
end

function ZO_CraftingResults_Keyboard:Initialize(control)
    local DONT_SHOW_IN_GAMEPAD_PREFERRED_MODE = false
    ZO_CraftingResults_Base.Initialize(self, control, DONT_SHOW_IN_GAMEPAD_PREFERRED_MODE)

    RegisterEnchantDialog("ENCHANT_TRANSLATION_LEARNED", ZO_CraftingResultEnchantDialog)

    local options = {
        colorItemName = true,
        centerAlignTraits = true,
        rowSpacing = 40,
    }

    RegisterAlchemyDialog("ALCHEMY_TRAITS_LEARNED", ZO_CraftingResultAlchemyDialog, options)
end

function ZO_CraftingResults_Keyboard:ModifyAnchor(newAnchor)
    ZO_CraftingResults_Base.ModifyAnchor(self, ZO_CraftingResultsTopLevel, newAnchor)
end

function ZO_CraftingResults_Keyboard:RestoreAnchor()
    ZO_CraftingResults_Base.RestoreAnchor(self, ZO_CraftingResultsTopLevel)
end

do
    local function SetupItem(control, data)
        if data.color then
            control:SetColor(data.color:UnpackRGB())
        else
            control:SetColor(ZO_SELECTED_TEXT:UnpackRGB())
        end

        control:SetText(data.text)

        local inventorySlot = control:GetNamedChild("Button")
        ZO_Inventory_SetupSlot(inventorySlot, data.stack, data.icon, data.meetsUsageRequirement)
    end

    local function EntryEqualitySetup(fadingControlBuffer, oldEntry, newEntry)
        local oldData = oldEntry.lines[1]
        local newData = newEntry.lines[1]
        oldData.stack = oldData.stack + newData.stack

        local inventorySlot = ZO_FadingControlBuffer_GetLineControl(oldData):GetNamedChild("Button")
        ZO_Inventory_SetupSlot(inventorySlot, oldData.stack, newData.icon, newData.meetsUsageRequirement)

        ZO_CraftingResults_Base_PlayPulse(inventorySlot)
    end

    function ZO_CraftingResults_Keyboard:AreCraftingResultLinesEqual(oldLines, newLines)
        return self:AreCraftingResultsEqual(oldLines[1], newLines[1])
    end

    function ZO_CraftingResults_Keyboard:InitializeResultBuffer()
        local anchor = ZO_Anchor:New(TOP)

        self.notifier = ZO_FadingControlBuffer:New(self.control, 5, nil, nil, "CraftingResultFade", "CraftingResultTranslate", anchor)
        self.notifier:SetTranslateDuration(500)
        self.notifier:SetHoldTimes(5000)
        self.notifier:SetFadesInImmediately(true)
        self.notifier:SetAdditionalVerticalSpacing(5)
        self.notifier:SetDisplayOlderEntriesFirst(true)

        local templateData =
        {
            setup = SetupItem,
            equalityCheck = function(...) return self:AreCraftingResultLinesEqual(...) end,
            equalitySetup = EntryEqualitySetup,
        }
        self.notifier:AddTemplate(CRAFTING_RESULTS_TEMPLATE, templateData)

        local function OnLastControlReleased()
            if self.isCurrentlyRegisteredWithCSAs then
                --Tell CSA to release handle
                self.isCurrentlyRegisteredWithCSAs = false
                CENTER_SCREEN_ANNOUNCE:ReleaseExternalHandle()
            end
        end
        self.notifier:RegisterCallback("LastControlReleased", OnLastControlReleased)
    end
end

function ZO_CraftingResults_Keyboard:IsActive()
    return not IsInGamepadPreferredMode()
end

function ZO_CraftingResults_Keyboard:ResumeCraftingResults()
    if self.isCurrentlyRegisteredWithCSAs then
        self.notifier:SetHoldDisplayingEntries(false)
        return true
    else
        return false
    end
end

function ZO_CraftingResults_Keyboard:DisplayCraftingResult(resultData)
    if not self.isCurrentlyRegisteredWithCSAs then
        self.isCurrentlyRegisteredWithCSAs = true
        self.notifier:SetHoldDisplayingEntries(true)

        --Hook the crafting results into the CSA system
        local messageParams = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_EXTERNAL_HANDLE)
        messageParams:SetCSAType(CENTER_SCREEN_ANNOUNCE_TYPE_CRAFTING_RESULTS)
        messageParams:SetExternalHandleCallback(function() return self:ResumeCraftingResults() end)
        CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(messageParams)
    end

    local resultEntryData = ZO_EntryData:New(resultData)
    -- Alias for backwards compatibility:
    resultEntryData.entryColor = resultData.color

    if ZO_RETRAIT_STATION_MANAGER:IsRetraitFragmentShowing() then
        local itemTrait = GetItemLinkTraitInfo(resultData.itemLink)
        local itemTraitString = GetString("SI_ITEMTRAITTYPE", itemTrait)
        local itemNameString = resultData.color:Colorize(resultData.name)
        resultEntryData.text = zo_strformat(SI_KEYBOARD_RETRAIT_COMPLETED_RESULT_FORMATTER, itemNameString, itemTraitString)
    else
        resultEntryData.text = zo_strformat(SI_TOOLTIP_ITEM_NAME, resultData.name)
    end

    local displayData =
    {
        lines =
        {
            resultEntryData
        }
    }
    self.notifier:AddEntry(CRAFTING_RESULTS_TEMPLATE, displayData)
end

function ZO_CraftingResults_Keyboard:ClearAll()
    self.notifier:ClearAll()
end

function ZO_CraftingResults_Keyboard:HasEntries()
    return self.notifier:HasEntries()
end

function ZO_CraftingResults_Keyboard:FadeAll()
    self.notifier:FadeAll()
end

function ZO_CraftingResults_Keyboard:DisplayDiscoveredTraits()
    ZO_Dialogs_ShowDialog("ALCHEMY_TRAITS_LEARNED")
end

function ZO_CraftingResults_Keyboard:DisplayTranslatedRunes()
    ZO_Dialogs_ShowDialog("ENCHANT_TRANSLATION_LEARNED")
end

function ZO_CraftingResults_Keyboard:ShouldDisplayMessages()
    return true
end

function ZO_CraftingResults_Keyboard:OnHidden()
    self:ForceCompleteCraftProcess()
    self:ClearAll()

    --If the crafting results were already registered with the CSA system, we need to make sure we properly release everything
    if self.isCurrentlyRegisteredWithCSAs then
        self.notifier:SetHoldDisplayingEntries(false)
        self.isCurrentlyRegisteredWithCSAs = false
        CENTER_SCREEN_ANNOUNCE:ReleaseExternalHandle()
    end
end

function ZO_CraftingResults_Keyboard_Initialize(control)
    CRAFTING_RESULTS = ZO_CraftingResults_Keyboard:New(control)
    SYSTEMS:RegisterKeyboardObject("craftingResults", CRAFTING_RESULTS)

    CRAFTING_RESULTS_FRAGMENT = ZO_FadeSceneFragment:New(control)
    CRAFTING_RESULTS_FRAGMENT:RegisterCallback("StateChange", function(oldState, newState)
        if newState == SCENE_HIDDEN then
            CRAFTING_RESULTS:OnHidden()
        end
    end)
end
