local NS = rawget(_G, "MCDVoiceCooldownNS") or {}
_G.MCDVoiceCooldownNS = NS

NS.UI = NS.UI or {}
NS.UI.EditorFields = NS.UI.EditorFields or {}

local Fields = NS.UI.EditorFields
local Widgets = NS.UI.Widgets
local Layout = NS.UI.EditorLayout or {}
local SoundFields = NS.UI.EditorSoundFields or {}
local L = NS.L or function(key, ...) if select("#", ...) > 0 then return string.format(tostring(key), ...) end return tostring(key) end

local SetNativeLabelColor = Layout.SetNativeLabelColor
local SetEnabled = Layout.SetEnabled
local SetTabVisual = Layout.SetTabVisual
local SetManyShown = Layout.SetManyShown

local function BuildDropdownItems(values)
    local items = {}
    for value, text in pairs(values or {}) do
        items[#items + 1] = {
            value = value,
            text = text,
        }
    end
    table.sort(items, function(a, b)
        if tonumber(a.value) == 0 and tonumber(b.value) ~= 0 then
            return true
        end
        if tonumber(b.value) == 0 and tonumber(a.value) ~= 0 then
            return false
        end
        return tostring(a.text or "") < tostring(b.text or "")
    end)
    return items
end

local DropdownItemCache = {}

local function ClearDropdownItemCache()
    for key in pairs(DropdownItemCache) do
        DropdownItemCache[key] = nil
    end
end

local function GetCachedClassItems()
    if not DropdownItemCache.classItems then
        DropdownItemCache.classItems = BuildDropdownItems(NS.AceOptions:GetClassValues())
    end
    return DropdownItemCache.classItems
end

local function GetCachedSpecItems(classID)
    local key = "spec:" .. tostring(classID or 0)
    if not DropdownItemCache[key] then
        DropdownItemCache[key] = BuildDropdownItems(NS.AceOptions:GetSpecValues(classID))
    end
    return DropdownItemCache[key]
end



function Fields:ClearDropdownItemCache()
    ClearDropdownItemCache()
    if SoundFields and type(SoundFields.ClearDropdownItemCache) == "function" then
        SoundFields:ClearDropdownItemCache()
    end
end

function Fields:PullFromWidgets(editor)
    if not editor.frame or not editor.frame:IsShown() then
        return
    end

    local widgets = editor.frame.widgets
    local state = NS.AceOptions:GetState()
    local modeTts, modeSound = NS.API.GetModes()

    if tostring(state.entryType or "") == "bloodlust" then
        state.bloodlustPaths = state.bloodlustPaths or {}
        for i = 1, 5 do
            state.bloodlustPaths[i] = NS.AceOptions:NormalizeSoundPath((widgets.bloodlustFields[i] and widgets.bloodlustFields[i]:GetText()) or "")
        end
        return
    end

    state.classID = tonumber(Widgets:GetDropdownValue(widgets.classDrop)) or 0
    if state.classID == 0 then
        state.specID = 0
    else
        state.specID = tonumber(Widgets:GetDropdownValue(widgets.specDrop)) or 0
    end
    state.spellId = tonumber(widgets.spellId:GetText() or "") or 0
    state.spellName = tostring(widgets.spellName:GetText() or "")
    state.baseCD = tonumber(widgets.baseCD:GetText() or "") or 0
    state.fixedCD = true
    state.checkTalent = widgets.checkTalent and widgets.checkTalent:GetChecked() == true or false
    state.talentId = tonumber((widgets.talentId and widgets.talentId:GetText()) or "") or 0
    state.talentName = tostring((widgets.talentName and widgets.talentName:GetText()) or "")
    state.talentCD = tonumber((widgets.talentCD and widgets.talentCD:GetText()) or "") or 0
    state.delayEnabled = widgets.delayEnabled and widgets.delayEnabled:GetChecked() == true or false
    state.delaySeconds = math.max(0, tonumber((widgets.delaySeconds and widgets.delaySeconds:GetText()) or "") or 0)
    if SoundFields and type(SoundFields.PullFromWidgets) == "function" then
        SoundFields:PullFromWidgets(widgets, state, modeTts, modeSound)
    end
end

function Fields:PushToWidgets(editor)
    local frame = editor:EnsureFrame()
    local widgets = frame.widgets
    local state = NS.AceOptions:GetState()
    local modeTts, modeSound = NS.API.GetModes()
    local soundFields, source, isTts = nil, tostring(state.soundSource or "builtin"), false
    if SoundFields and type(SoundFields.ResolveState) == "function" then
        soundFields, source, isTts = SoundFields:ResolveState(state, modeTts, modeSound)
    else
        soundFields = NS.AceOptions:ResolveSoundSourceFields(state, modeTts, modeSound)
        source = tostring(soundFields.soundSource or state.soundSource or "builtin")
        isTts = source == "tts" or tostring(state.notifyMode or "") == tostring(modeTts)
    end
    local isCooldown = tostring(state.entryType or "cooldown") == "cooldown"
    local isBloodlust = tostring(state.entryType or "") == "bloodlust"
    local isCast = (not isCooldown) and (not isBloodlust)

    local normalControls = {
        widgets.classSection,
        widgets.spellSection,
        widgets.notifySection,
        widgets.classLabel,
        widgets.specLabel,
        widgets.spellIdLabel,
        widgets.spellNameLabel,
        widgets.talentIdLabel,
        widgets.talentNameLabel,
        widgets.talentCDLabel,
        widgets.baseCDLabel,
        widgets.sourceLabel,
        widgets.builtinLabel,
        widgets.sharedMediaLabel,
        widgets.customPathLabel,
        widgets.ttsTextLabel,
        widgets.rateLabel,
        widgets.classDrop,
        widgets.specDrop,
        widgets.spellId,
        widgets.spellName,
        widgets.checkTalent,
        widgets.talentId,
        widgets.talentName,
        widgets.talentCD,
        widgets.delayEnabled,
        widgets.delaySecondsLabel,
        widgets.delaySeconds,
        widgets.baseCD,
        widgets.sourceDrop,
        widgets.builtinDrop,
        widgets.sharedMediaDrop,
        widgets.ttsText,
        widgets.ttsRateSlider,
        widgets.soundPath,
        widgets.editorHint,
    }
    local bloodlustControls = {
        widgets.bloodlustSection,
        widgets.bloodlustSummary,
        widgets.bloodlustHint,
    }

    for _, item in ipairs(widgets.bloodlustLabels or {}) do
        bloodlustControls[#bloodlustControls + 1] = item
    end
    for _, item in ipairs(widgets.bloodlustFields or {}) do
        bloodlustControls[#bloodlustControls + 1] = item
    end

    SetManyShown(normalControls, not isBloodlust)
    SetManyShown(bloodlustControls, isBloodlust)

    if isBloodlust then
        frame.title:SetText(L("TITLE_BLOODLUST_SETTINGS"))
        if widgets.bloodlustSummary then
            widgets.bloodlustSummary:SetText(NS.AceOptions:GetBloodlustSummary())
        end
        state.bloodlustPaths = state.bloodlustPaths or { "", "", "", "", "" }
        for i = 1, 5 do
            if widgets.bloodlustFields[i] then
                widgets.bloodlustFields[i]:SetText(tostring(state.bloodlustPaths[i] or ""))
            end
        end
        SetTabVisual(widgets.tabCooldown, false)
        SetTabVisual(widgets.tabCast, false)
        SetTabVisual(widgets.tabBloodlust, true)
        return
    end

    frame.title:SetText(editor.mode == "new" and L("TITLE_NEW_CONFIG") or L("TITLE_EDIT_CONFIG"))

    Widgets:SetDropdownItems(widgets.classDrop, GetCachedClassItems())
    Widgets:SetDropdownValue(widgets.classDrop, state.classID, L("PLACEHOLDER_SELECT_CLASS"))

    if (tonumber(state.classID) or 0) == 0 then
        state.specID = 0
    end
    local specDropdownEnabled = (tonumber(state.classID) or 0) ~= 0
    Widgets:SetDropdownItems(widgets.specDrop, GetCachedSpecItems(state.classID))
    Widgets:SetDropdownValue(widgets.specDrop, state.specID, L("PLACEHOLDER_SELECT_SPEC"))
    Widgets:SetDropdownEnabled(widgets.specDrop, specDropdownEnabled)
    if widgets.specLabel then
        SetNativeLabelColor(widgets.specLabel, specDropdownEnabled)
    end

    widgets.spellId:SetText((tonumber(state.spellId) or 0) > 0 and tostring(state.spellId) or "")
    widgets.spellName:SetText(tostring(state.spellName or ""))
    widgets.checkTalent:SetChecked(state.checkTalent == true)
    widgets.talentId:SetText((tonumber(state.talentId) or 0) > 0 and tostring(state.talentId) or "")
    widgets.talentName:SetText(tostring(state.talentName or ""))
    if widgets.talentCD then
        widgets.talentCD:SetText((tonumber(state.talentCD) or 0) > 0 and tostring(state.talentCD) or "")
    end
    if widgets.delayEnabled then
        widgets.delayEnabled:SetChecked(state.delayEnabled == true)
    end
    if widgets.delaySeconds then
        widgets.delaySeconds:SetText((tonumber(state.delaySeconds) or 0) > 0 and tostring(state.delaySeconds) or "")
    end
    widgets.baseCD:SetText((tonumber(state.baseCD) or 0) > 0 and tostring(state.baseCD) or "")
    state.fixedCD = true
    widgets.talentIdLabel:SetShown(isCooldown)
    widgets.talentNameLabel:SetShown(isCooldown)
    if widgets.talentCDLabel then
        widgets.talentCDLabel:SetShown(isCooldown)
    end
    widgets.baseCDLabel:SetShown(isCooldown)
    widgets.checkTalent:SetShown(isCooldown)
    widgets.talentId:SetShown(isCooldown)
    widgets.talentName:SetShown(isCooldown)
    if widgets.talentCD then
        widgets.talentCD:SetShown(isCooldown)
    end
    widgets.baseCD:SetShown(isCooldown)
    if widgets.delayEnabled then
        widgets.delayEnabled:SetShown(isCast)
    end
    if widgets.delaySecondsLabel then
        widgets.delaySecondsLabel:SetShown(isCast)
    end
    if widgets.delaySeconds then
        widgets.delaySeconds:SetShown(isCast)
    end

    local talentEnabled = isCooldown and (state.checkTalent == true)
    SetEnabled(widgets.checkTalent, isCooldown)
    SetEnabled(widgets.talentId, talentEnabled)
    SetEnabled(widgets.talentName, talentEnabled)
    if widgets.talentCD then
        SetEnabled(widgets.talentCD, talentEnabled)
    end
    if widgets.talentIdLabel then
        SetNativeLabelColor(widgets.talentIdLabel, talentEnabled)
    end
    if widgets.talentNameLabel then
        SetNativeLabelColor(widgets.talentNameLabel, talentEnabled)
    end
    if widgets.talentCDLabel then
        SetNativeLabelColor(widgets.talentCDLabel, talentEnabled)
    end

    local delayInputEnabled = isCast and (state.delayEnabled == true)
    if widgets.delayEnabled then
        SetEnabled(widgets.delayEnabled, isCast)
    end
    if widgets.delaySeconds then
        SetEnabled(widgets.delaySeconds, delayInputEnabled)
    end
    if widgets.delaySecondsLabel then
        SetNativeLabelColor(widgets.delaySecondsLabel, delayInputEnabled)
    end

    SetEnabled(widgets.baseCD, isCooldown)
    Widgets:SetDropdownEnabled(widgets.sourceDrop, true)

    if SoundFields and type(SoundFields.PushToWidgets) == "function" then
        SoundFields:PushToWidgets(widgets, state, soundFields, source, isTts)
    end

    SetTabVisual(widgets.tabCooldown, isCooldown)
    SetTabVisual(widgets.tabCast, isCast)
    SetTabVisual(widgets.tabBloodlust, false)
end


local function SetLocaleText(target, text)
    if target and target.SetText then
        target:SetText(text)
    end
end

local function SetSectionLocaleText(section, text)
    if not section then
        return
    end
    if section.label and section.label.SetText then
        section.label:SetText(text)
    elseif section.mcdLabel and section.mcdLabel.SetText then
        section.mcdLabel:SetText(text)
    end
end

local function SetCheckButtonLocaleText(button, text)
    if not button then
        return
    end
    local label = (type(button.mcdLabel) == "table" and button.mcdLabel)
        or (type(button.Text) == "table" and button.Text)
        or (type(button.text) == "table" and button.text)
    if label and label.SetText then
        label:SetText(text)
        if label.SetWordWrap then label:SetWordWrap(false) end
        if label.SetMaxLines then label:SetMaxLines(1) end
        if label.SetWidth then
            label:SetWidth(math.max(1, (tonumber(button.mcdMaxWidth) or 180) - 30))
        end
    end
    if button.SetSize then
        button:SetSize(24, 24)
    end
    if button.SetHitRectInsets then
        button:SetHitRectInsets(0, -math.max(0, (tonumber(button.mcdMaxWidth) or 180) - 30), 0, 0)
    end
end

-- 语言切换时仅刷新静态文案，不 PushToWidgets，避免覆盖编辑框里尚未保存的输入。
function Fields:RefreshLocale(editor)
    if not editor.frame then
        return
    end

    ClearDropdownItemCache()
    if SoundFields and type(SoundFields.ClearDropdownItemCache) == "function" then
        SoundFields:ClearDropdownItemCache()
    end

    local frame = editor.frame
    local widgets = frame.widgets or {}
    local state = NS.AceOptions and NS.AceOptions.GetState and NS.AceOptions:GetState() or {}
    local entryType = tostring(state.entryType or "cooldown")

    if frame.title then
        if entryType == "bloodlust" then
            frame.title:SetText(L("TITLE_BLOODLUST_SETTINGS"))
        else
            frame.title:SetText(editor.mode == "new" and L("TITLE_NEW_CONFIG") or L("TITLE_EDIT_CONFIG"))
        end
    end

    SetLocaleText(frame.description, L("EDITOR_DESC"))
    SetLocaleText(widgets.tabCooldown, L("TAB_COOLDOWN"))
    SetLocaleText(widgets.tabCast, L("TAB_CAST"))
    SetLocaleText(widgets.tabBloodlust, L("TAB_BLOODLUST"))
    SetLocaleText(widgets.actionSave, L("BTN_SAVE"))
    SetLocaleText(widgets.actionTest, L("BTN_TEST"))

    SetSectionLocaleText(widgets.classSection, L("SECTION_CLASS_SPEC"))
    SetSectionLocaleText(widgets.spellSection, L("SECTION_SPELL_PARAMS"))
    SetSectionLocaleText(widgets.notifySection, L("SECTION_NOTIFY"))
    SetSectionLocaleText(widgets.bloodlustSection, L("SECTION_BLOODLUST_SOUND"))

    SetLocaleText(widgets.classLabel, L("LABEL_CLASS"))
    SetLocaleText(widgets.specLabel, L("LABEL_SPEC"))
    SetLocaleText(widgets.spellIdLabel, L("LABEL_SPELL_ID"))
    SetLocaleText(widgets.spellNameLabel, L("LABEL_SPELL_NAME"))
    SetLocaleText(widgets.baseCDLabel, L("LABEL_FIXED_CD_SEC"))
    SetLocaleText(widgets.talentIdLabel, L("LABEL_TALENT_ID"))
    SetLocaleText(widgets.talentNameLabel, L("LABEL_TALENT_NAME"))
    SetLocaleText(widgets.talentCDLabel, L("LABEL_TALENT_CD_SEC"))
    SetLocaleText(widgets.delaySecondsLabel, L("LABEL_DELAY_SECONDS"))
    SetLocaleText(widgets.sourceLabel, L("LABEL_SOUND_SOURCE"))
    SetLocaleText(widgets.builtinLabel, L("LABEL_BUILTIN_SOUND"))
    SetLocaleText(widgets.sharedMediaLabel, L("LABEL_SHAREDMEDIA_SOUND"))
    SetLocaleText(widgets.customPathLabel, L("LABEL_CUSTOM_SOUND_PATH"))
    SetLocaleText(widgets.ttsTextLabel, L("LABEL_TTS_TEXT"))
    SetLocaleText(widgets.rateLabel, L("LABEL_TTS_RATE"))
    SetLocaleText(widgets.editorHint, L("EDITOR_HINT"))
    SetLocaleText(widgets.bloodlustHint, L("BLOODLUST_HINT"))

    SetCheckButtonLocaleText(widgets.checkTalent, L("LABEL_CHECK_TALENT"))
    SetCheckButtonLocaleText(widgets.delayEnabled, L("LABEL_DELAY_CAST_SUCCESS"))

    for i = 1, 5 do
        SetLocaleText(widgets.bloodlustLabels and widgets.bloodlustLabels[i], L("LABEL_SOUND_PATH_N", i))
    end

    if widgets.bloodlustSummary and NS.AceOptions and type(NS.AceOptions.GetBloodlustSummary) == "function" then
        widgets.bloodlustSummary:SetText(NS.AceOptions:GetBloodlustSummary())
    end

    if frame:IsShown() then
        frame:Raise()
    end
end

