-- RUQuestLog_List.lua (TBCC 2.5.5)
-- Only:
--  - zone headers in the LEFT quest log list
--  - quest titles in the LEFT quest log list
--  - selected quest title in the RIGHT panel (header only)
--
-- Saved flag:
--   RUQuestLogDB.enabled (default true)
--
-- Slash:
--   /ruql on | off

local ADDON = ...

local function isEnabled()
    return RUQuestLogDB and RUQuestLogDB.enabled ~= false
end

local function chat(msg)
    if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
        DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffRUQL|r " .. tostring(msg))
    end
end

-- forward declarations NOTE: must be before first use
local walkFontStrings

-- заполняй по мере нужды
local ZONE_RU = {
  -- Eastern Kingdoms
  ["Elwynn Forest"] = "Элвиннский лес",
  ["Dun Morogh"] = "Дун Морог",
  ["Tirisfal Glades"] = "Тирисфальские леса",
  ["Westfall"] = "Западный Край",
  ["Loch Modan"] = "Лок Модан",
  ["Redridge Mountains"] = "Красногорье",
  ["Duskwood"] = "Сумеречный лес",
  ["Wetlands"] = "Болотина",
  ["Hillsbrad Foothills"] = "Предгорья Хилсбрада",
  ["Arathi Highlands"] = "Нагорье Арати",
  ["Stranglethorn Vale"] = "Тернистая долина",
  ["Swamp of Sorrows"] = "Болото Печали",
  ["Blasted Lands"] = "Выжженные земли",
  ["Badlands"] = "Бесплодные земли",
  ["Searing Gorge"] = "Тлеющее ущелье",
  ["Burning Steppes"] = "Пылающие степи",
  ["Western Plaguelands"] = "Западные Чумные земли",
  ["Eastern Plaguelands"] = "Восточные Чумные земли",
  ["Deadwind Pass"] = "Перевал Мёртвого Ветра",
  ["Silverpine Forest"] = "Серебряный бор",
  ["Alterac Mountains"] = "Альтеракские горы",
  ["The Hinterlands"] = "Внутренние земли",

  -- Kalimdor
  ["Durotar"] = "Дуротар",
  ["Mulgore"] = "Мулгор",
  ["Teldrassil"] = "Тельдрассил",
  ["Darkshore"] = "Тёмные берега",
  ["Barrens"] = "Степи",
  ["The Barrens"] = "Степи",
  ["Stonetalon Mountains"] = "Когтистые горы",
  ["Ashenvale"] = "Ясеневый лес",
  ["Thousand Needles"] = "Тысяча Игл",
  ["Desolace"] = "Пустоши",
  ["Dustwallow Marsh"] = "Пылевые топи",
  ["Feralas"] = "Фералас",
  ["Tanaris"] = "Танарис",
  ["Azshara"] = "Азшара",
  ["Felwood"] = "Осквернённый лес",
  ["Un'Goro Crater"] = "Кратер Ун'Горо",
  ["Silithus"] = "Силитус",
  ["Winterspring"] = "Зимние Ключи",
  ["Moonglade"] = "Лунная поляна",

  -- Cities
  ["Stormwind City"] = "Штормград",
  ["Ironforge"] = "Стальгорн",
  ["Darnassus"] = "Дарнас",
  ["Orgrimmar"] = "Оргриммар",
  ["Thunder Bluff"] = "Громовой Утёс",
  ["Undercity"] = "Подгород",
  ["Silvermoon City"] = "Луносвет",
  ["Exodar"] = "Экзодар",
  ["Shattrath City"] = "Шаттрат",

  -- TBC: Outland
  ["Hellfire Peninsula"] = "Полуостров Адского Пламени",
  ["Zangarmarsh"] = "Зангартопь",
  ["Terokkar Forest"] = "Лес Тероккар",
  ["Nagrand"] = "Награнд",
  ["Blade's Edge Mountains"] = "Острогорье",
  ["Netherstorm"] = "Пустоверть",
  ["Shadowmoon Valley"] = "Долина Призрачной Луны",

  -- Instances / special (часто попадаются как заголовки)
  ["Blackrock Depths"] = "Глубины Чёрной горы",
  ["Blackrock Spire"] = "Пик Чёрной горы",
  ["Dire Maul"] = "Забытый Город",
  ["Maraudon"] = "Мародон",
  ["Scarlet Monastery"] = "Монастырь Алого ордена",
  ["Stratholme"] = "Стратхольм",
  ["Scholomance"] = "Некроситет",
  ["Ragefire Chasm"] = "Огненная пропасть",
  ["Wailing Caverns"] = "Пещеры Стенаний",
  ["Deadmines"] = "Мёртвые копи",
  ["Shadowfang Keep"] = "Крепость Темного Клыка",
  ["Zul'Farrak"] = "Зул'Фаррак",
  ["Zul'Gurub"] = "Зул'Гуруб",
  ["Ahn'Qiraj"] = "Ан'Кираж",
  ["Timbermaw Hold"] = "Древобрюхи",

  -- ПОЛЯ БОЯ (ВСЕ)
  ["Warsong Gulch"] = "Ущелье Песни Войны",
  ["Arathi Basin"] = "Низина Арати",
  ["Alterac Valley"] = "Альтеракская долина",
  ["Eye of the Storm"] = "Око Бури",

  -- иногда в журнале встречаются так
  ["Battle for Warsong Gulch"] = "Ущелье Песни Войны",
  ["Battle for Arathi Basin"] = "Низина Арати",
  ["Battle for Alterac Valley"] = "Альтеракская долина",
}

-- служебные

walkFontStrings = function(frame, out)
    if not frame then return end

    if frame.GetRegions then
        local regions = { frame:GetRegions() }
        for _, r in ipairs(regions) do
            if r and r.GetObjectType and r:GetObjectType() == "FontString" then
                out[#out + 1] = r
            end
        end
    end

    if frame.GetNumChildren then
        for i = 1, frame:GetNumChildren() do
            walkFontStrings(select(i, frame:GetChildren()), out)
        end
    end
end

local function importMultiLanguageRu()
    if not MultiLanguageQuestData or not MultiLanguageQuestData["ru"] then
        return 0
    end

    local src = MultiLanguageQuestData["ru"]
    local n = 0

    local function clean(s)
        if type(s) ~= "string" or s == "" then
            return nil
        end
        s = s:gsub("\r\n", "\n"):gsub("\r", "\n")
        s = s:gsub("%s*<<Do Not Localize>>%s*", "")
        return s
    end

    for questID, row in pairs(src) do
        if type(questID) == "number" and type(row) == "table" then
            -- если квест уже есть — ничего не делаем
            if RUQuestLogDB.quest[questID] == nil then
                local dst = {}

                local title       = clean(row.title)
                local objectives  = clean(row.objective)     -- objective -> objectives
                local details     = clean(row.description)   -- description -> details
                local progress    = clean(row.progress)
                local completion  = clean(row.completion)
                local rewardsTxt  = clean(row.rewards)

                if title then dst.title = title end
                if objectives then dst.objectives = objectives end
                if details then dst.details = details end
                if progress then dst.progress = progress end
                if completion then dst.completion = completion end
                if rewardsTxt then dst.rewardsText = rewardsTxt end

                RUQuestLogDB.quest[questID] = dst
                n = n + 1
            end
        end
    end

    return n
end

local function getRuZone(en)
  if not en then return nil end
  return ZONE_RU[en] or ZONE_RU[en:gsub("^%s+", ""):gsub("%s+$", "")]
end

local function getSelectedQuestID_255()
    if not (GetQuestLogSelection and GetQuestLogTitle) then
        return nil
    end
    local sel = GetQuestLogSelection() or 0
    if sel <= 0 then
        return nil
    end
    local questID = select(8, GetQuestLogTitle(sel))
    if type(questID) == "number" and questID > 0 then
        return questID
    end
    return nil
end

local function getRuQuestTitle(questID)
    local db = RUQuestLogDB and RUQuestLogDB.quest
    local row = db and questID and db[questID]
    return row and row.title or nil
end

-- Right journal Content
local function setRuFontSafe(fs, size, flags)
  if not (fs and fs.SetFont) then return false end

  local path1 = "Interface\\AddOns\\" .. tostring(ADDON) .. "\\Fonts\\Morpheus.ttf"
  local path2 = "Fonts\\MORPHEUS.ttf"

  flags = flags or ""
  size = size or 16

  local ok = false

  local ok1 = pcall(function()
    ok = fs:SetFont(path1, size, flags) and true or false
  end)
  if ok1 and ok then
    return true
  end

  local ok2 = pcall(function()
    ok = fs:SetFont(path2, size, flags) and true or false
  end)
  if ok2 and ok then
    return true
  end

  return false
end

local function setRuObjectivesFont(fs)
    return fs
end

local function applyQuestLogRightTitle()
    if not isEnabled() then return end
    if not (QuestLogFrame and QuestLogFrame:IsShown()) then return end

    local qid = getSelectedQuestID_255()
    if not qid then return end

    local ru = getRuQuestTitle(qid)
    if not ru or ru == "" then return end
    ru = RUQL_post(ru)

    if QuestLogQuestTitle and QuestLogQuestTitle.SetText then
        -- сначала пытаемся поставить кириллический шрифт, потом текст
        RUQL_setRuTitleFont(QuestLogQuestTitle)
        QuestLogQuestTitle:SetText(ru)
    end

    if QuestLogTitleText and QuestLogTitleText.SetText then
        QuestLogTitleText:SetText(ru)
    end
end

local function applyQuestLogRightObjectives()
    if not isEnabled() then
        return
    end
    if not (QuestLogFrame and QuestLogFrame:IsShown()) then
        return
    end

    local qid = getSelectedQuestID_255()
    if not qid then
        return
    end

    local row = RUQuestLogDB and RUQuestLogDB.quest and RUQuestLogDB.quest[qid]
    if not row then
        return
    end

    local ruObj = RUQL_normalize(row.objectives)
    if not ruObj or ruObj == "" then
        return
    end

    local ruTitle = RUQL_normalize(row.title) or ""
    local header
    if ruTitle ~= "" then
        header = ruTitle .. " [" .. tostring(qid) .. "]"
    else
        header = "[" .. tostring(qid) .. "]"
    end

    local finalText = ruObj -- header .. "\n\n" .. ruObj

    -- Лейбл OBJECTIVES -> Цели
    if QuestLogObjectivesTitle and QuestLogObjectivesTitle.SetText then
        QuestLogObjectivesTitle:SetText("Цели")
    end

    -- тело objectives по частым именам
    local appliedBody = false
    local candidates = {
        "QuestLogObjectivesText",
        "QuestLogObjectiveText",
        "QuestLogObjectivesTextScrollChildFrameText",
        "QuestLogObjectivesScrollChildFrameText",
        "QuestLogObjectivesScrollChildFrameTextText",
    }
    for _, name in ipairs(candidates) do
        local fs = _G[name]
        if fs and fs.SetText then
            setRuObjectivesFont(fs)
            fs:SetText(RUQL_post(finalText))
            appliedBody = true
        end
    end

    -- если по именам не попали — ищем совпадение с текущим objectives из API
    local apiDesc, apiObj
    if GetQuestLogQuestText then
        apiDesc, apiObj = GetQuestLogQuestText()
        apiObj = RUQL_normalize(apiObj)
    end

    local list = {}
    walkFontStrings(QuestLogFrame, list)

    for _, fs in ipairs(list) do
        local t = RUQL_normalize(fs:GetText())
        if t and t ~= "" then
            if t == "OBJECTIVES" then
                fs:SetText("Цели")
            end

            if not appliedBody and apiObj and t == apiObj then
                setRuObjectivesFont(fs)
                fs:SetText(RUQL_post(finalText))
                appliedBody = true
            end
        end
    end
end

local function applyQuestLogRightDescription()
    if not isEnabled() then return end
    if not (QuestLogFrame and QuestLogFrame:IsShown()) then return end

    local qid = getSelectedQuestID_255()
    if not qid then return end

    local row = RUQuestLogDB and RUQuestLogDB.quest and RUQuestLogDB.quest[qid]
    if not row then return end

    local ruDetails = RUQL_normalize(row.details)
    if not ruDetails or ruDetails == "" then return end

    -- 1) Заголовок DESCRIPTION -> Описание (и шрифт как у title)
    if QuestLogDescriptionTitle and QuestLogDescriptionTitle.SetText then
        RUQL_setRuTitleFont(QuestLogDescriptionTitle)
        QuestLogDescriptionTitle:SetText("Описание")
    end

    -- 2) тело описания по именам (и шрифт как у objectives)
    local appliedBody = false
    local candidates = {
        "QuestLogDescriptionText",
        "QuestLogDetailsText",
        "QuestLogDescriptionTextScrollChildFrameText",
        "QuestLogDetailScrollChildFrameText",
        "QuestLogDetailsScrollChildFrameText",
    }
    for _, name in ipairs(candidates) do
        local fs = _G[name]
        if fs and fs.SetText then
            setRuObjectivesFont(fs)
            fs:SetText(RUQL_post(ruDetails))
            appliedBody = true
        end
    end

    -- 3) fallback: ищем текущее описание из API и подменяем только тело
    local apiDesc
    if GetQuestLogQuestText then
        apiDesc = RUQL_normalize((GetQuestLogQuestText()))
    end

    local list = {}
    walkFontStrings(QuestLogFrame, list)

    for _, fs in ipairs(list) do
        local t = RUQL_normalize(fs:GetText())
        if t and t ~= "" then
            if t == "DESCRIPTION" then
                RUQL_setRuTitleFont(fs)
                fs:SetText("Описание")
            end

            if not appliedBody and apiDesc and t == apiDesc then
                setRuObjectivesFont(fs)
                fs:SetText(RUQL_post(ruDetails))
                appliedBody = true
            end
        end
    end
end

local function applyQuestLogRightRewardsLabels()
    if not isEnabled() then return end
    if not (QuestLogFrame and QuestLogFrame:IsShown()) then return end

    local list = {}
    walkFontStrings(QuestLogFrame, list)

    for _, fs in ipairs(list) do
        local t = RUQL_normalize(fs:GetText())
        if t and t ~= "" then
            local tl = t:lower()

            if tl == "rewards" then
                RUQL_setRuTitleFont(fs)
                fs:SetText("Награды")

            elseif tl:find("you will receive", 1, true) then
                fs:SetText("Вы получите:")

            elseif tl:find("you will be able to choose one of these rewards", 1, true) then
                fs:SetText("Вы сможете выбрать одну из этих наград:")

            elseif tl:find("you will also receive", 1, true) then
                fs:SetText("Также вы получите:")

            elseif tl:find("bonus honor", 1, true) then
                fs:SetText(t:gsub("[Bb]onus [Hh]onor", "Дополнительная честь"))
            end
        end
    end
end

-- СТАРТ
local function applyQuestLogList()
    if not isEnabled() then
        return
    end
    if not (QuestLogFrame and QuestLogFrame:IsShown()) then
        return
    end
    if not (GetNumQuestLogEntries and GetQuestLogTitle) then
        return
    end

    local numEntries = GetNumQuestLogEntries() or 0

    for i = 1, numEntries do
        local title, _, _, isHeader = GetQuestLogTitle(i)
        local btn = _G["QuestLogTitle" .. i]

        if btn and title and title ~= "" then
            if isHeader then
              local ruZone = getRuZone(title)
              btn:SetText(ruZone or title)
            else
                --local questID = select(8, GetQuestLogTitle(i))
                --local ru = questID and getRuQuestTitle(questID) or nil
                --btn:SetText(ru or title)
            end
        end
    end

    applyQuestLogRightTitle()
    applyQuestLogRightDescription()
    applyQuestLogRightObjectives()
    applyQuestLogRightRewardsLabels()

end

local function journalHooks()
    if QuestLog_Update then
        hooksecurefunc("QuestLog_Update", applyQuestLogList)
    end
    if QuestLogFrame and QuestLogFrame.HookScript then
        QuestLogFrame:HookScript("OnShow", applyQuestLogList)
    end
    if QuestLog_SetSelection then
        hooksecurefunc("QuestLog_SetSelection", function()
            applyQuestLogRightTitle()
            applyQuestLogRightDescription()
            applyQuestLogRightObjectives()
            applyQuestLogRightRewardsLabels()
        end)
    end

    return
end

local f = CreateFrame("Frame")
f:RegisterEvent("ADDON_LOADED")
f:RegisterEvent("QUEST_LOG_UPDATE")

f:SetScript("OnEvent", function(_, event, arg1)
    -- 1) Наш аддон загрузился
    if event == "ADDON_LOADED" and arg1 == ADDON then
        RUQuestLogDB = RUQuestLogDB or {}
        RUQuestLogDB.quest = RUQuestLogDB.quest or {}
        if RUQuestLogDB.enabled == nil then
            RUQuestLogDB.enabled = true
        end

        local imported = importMultiLanguageRu()
        if imported > 0 then
            chat("imported from MultiLanguageQuestData[ru]: " .. tostring(imported))
        end

        chat("loaded. /ruql on|off")

        journalHooks()

        return
    end

    -- 2) Обновление журнала
    if event == "QUEST_LOG_UPDATE" then
        applyQuestLogList()
        return
    end
end)

SLASH_RUQL1 = "/ruql"
SlashCmdList["RUQL"] = function(msgIn)
    local m = (msgIn or ""):lower()

    if m == "off" then
        RUQuestLogDB.enabled = false
        chat("off")
        return
    end

    if m == "on" then
        RUQuestLogDB.enabled = true
        chat("on")
        applyQuestLogList()
        return
    end

    chat("usage: /ruql on | off")
end