local ns = _G.WoWTranslate_UK_NS

local translator = setmetatable({}, { __index = ns.BaseTranslator })
translator.IsEnabled = translator.IsEnabled or function() return true end
ns.TranslationsManager:Add(translator)

local tooltipCache = {}
local CACHE_MAX = 4096
local cacheCount = 0

local creatureTypes = {
    Beast = "Звір", Humanoid = "Гуманоїд", Undead = "Нежить",
    Mechanical = "Механізм", Elemental = "Стихійник", Dragonkin = "Дракон",
    Demon = "Демон", Aberration = "Аберрація", Giant = "Велетень",
    Critter = "Тваринка", ["Not specified"] = "Не визначено",
}

local unitQualifiers = {
    Boss = "Бос",
    Elite = "Елітний",
    ["Rare Elite"] = "Рідкісний елітний",
    Rare = "Рідкісний",
    ["Rare-1"] = "Рідкісний",
    ["Rare-2"] = "Рідкісний",
}

local function sanitizeTooltipText(rawText)
    if type(rawText) ~= "string" or rawText == "" then
        return rawText, "", "", false
    end
    local colorPrefix = rawText:match("^(|c%x%x%x%x%x%x%x%x)") or ""
    local colorSuffix = rawText:match("(|r)$") or ""
    local clean = rawText:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
    local isTitle = false
    if clean:match("^<.+>$") then
        isTitle = true
        clean = clean:sub(2, -2)
    end
    return clean, colorPrefix, colorSuffix, isTitle
end

local function reassemble(translated, colorPrefix, colorSuffix, isTitle)
    if not translated then return nil end
    if isTitle then
        translated = "<" .. translated .. ">"
    end
    if colorPrefix ~= "" or colorSuffix ~= "" then
        translated = colorPrefix .. translated .. colorSuffix
    end
    return translated
end

local function applyLine(fontString, text, translated)
    if not translated or translated == text then
        if cacheCount >= CACHE_MAX then wipe(tooltipCache); cacheCount = 0 end
        tooltipCache[text] = false; cacheCount = cacheCount + 1
        return
    end
    if ns.resolvePlaceholders then
        translated = ns.resolvePlaceholders(translated)
    end
    if cacheCount >= CACHE_MAX then wipe(tooltipCache); cacheCount = 0 end
    tooltipCache[text] = translated; cacheCount = cacheCount + 1

    fontString._wt_updating = true
    fontString:SetText(translated)
    fontString._wt_updating = nil
    fontString._wt_tr = translated
    fontString._wt_orig = text

    if ns.hasCyrillic and ns.hasCyrillic(translated) and fontString.SetFont then
        if InCombatLockdown and InCombatLockdown() then return end
        local ok_f, fontFile, height, flags = pcall(fontString.GetFont, fontString)
        if ok_f and fontFile and ns.needsCyrillicFont and ns.needsCyrillicFont(fontFile) then
            local chosen = ns.selectFontForContext and ns.selectFontForContext(fontFile) or ns.PreferredFont
            pcall(fontString.SetFont, fontString, chosen, height or 13, flags or "")
        end
    end
end

local translateUnitTooltipLine

local function translateNameLine(fontString, unit)
    if not fontString then return end
    if ns.isProtectedFrame and ns.isProtectedFrame(fontString) then return end
    pcall(function()
        local ok_gt, text = pcall(fontString.GetText, fontString)
        if not ok_gt or type(text) ~= "string" or text == "" then return end

        local ok_cmp_tr, already = pcall(function() return fontString._wt_tr == text end)
        if ok_cmp_tr and already then return end

        local ok_cmp_orig, orig_match = pcall(function() return fontString._wt_orig == text end)
        if ok_cmp_orig and orig_match and fontString._wt_tr then
            fontString._wt_updating = true
            fontString:SetText(fontString._wt_tr)
            fontString._wt_updating = nil
            return
        end

        local cleanText = text:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
        local colorPrefix = text:match("^(|c%x%x%x%x%x%x%x%x)") or ""
        local colorSuffix = text:match("(|r)$") or ""

        local unitName = nil
        if unit then
            local ok_n, n = pcall(UnitName, unit)
            if ok_n and type(n) == "string" and n ~= "" then
                unitName = n
            end
        end

        local tr = nil

        if unitName then
            tr = ns.GetTranslation and ns.GetTranslation(unitName)
        end

        if not tr and cleanText ~= "" then
            tr = ns.GetTranslation and ns.GetTranslation(cleanText)
        end

        if not tr or tr == cleanText then
            translateUnitTooltipLine(fontString)
            return
        end

        local newLine
        if unitName and cleanText == unitName then
            newLine = colorPrefix .. tr .. colorSuffix
        elseif unitName and cleanText:find(unitName, 1, true) then
            newLine = cleanText:gsub(unitName:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1"), tr)
            if colorPrefix ~= "" or colorSuffix ~= "" then
                newLine = colorPrefix .. newLine .. colorSuffix
            end
        else
            newLine = colorPrefix .. tr .. colorSuffix
        end

        if newLine and newLine ~= text then
            applyLine(fontString, text, newLine)
        else
            translateUnitTooltipLine(fontString)
        end
    end)
end

translateUnitTooltipLine = function(fontString)
    if not fontString then return end
    if ns.isProtectedFrame and ns.isProtectedFrame(fontString) then return end
    pcall(function()
        local ok_gt, text = pcall(fontString.GetText, fontString)
        if not ok_gt or type(text) ~= "string" or text == "" then return end

        local ok_cmp_tr, already = pcall(function() return fontString._wt_tr == text end)
        if ok_cmp_tr and already then return end

        local ok_cmp_orig, orig_match = pcall(function() return fontString._wt_orig == text end)
        if ok_cmp_orig and orig_match and fontString._wt_tr then
            fontString._wt_updating = true
            fontString:SetText(fontString._wt_tr)
            fontString._wt_updating = nil
            return
        end

        local cacheHit = tooltipCache[text]
        if cacheHit ~= nil then
            if cacheHit and cacheHit ~= text then
                fontString._wt_updating = true
                fontString:SetText(cacheHit)
                fontString._wt_updating = nil
                fontString._wt_tr = cacheHit
                fontString._wt_orig = text
            end
            return
        end

        local cleanText, colorPrefix, colorSuffix, isTitle = sanitizeTooltipText(text)

        local translated = nil

        if cleanText ~= text then
            translated = ns.GetTranslation and ns.GetTranslation(cleanText)
            if not translated and ns.translateObjectiveLine then
                translated = ns.translateObjectiveLine(cleanText)
            end

            if not translated then
                local lvl, qual = cleanText:match("^Level ([%d%?]+) %((.-)%)$")
                if lvl and qual then
                    local transQual = unitQualifiers[qual]
                    if transQual then
                        translated = "Рівень " .. lvl .. " (" .. transQual .. ")"
                    else
                        local transFaction = ns.GetTranslation and ns.GetTranslation(qual) or qual
                        translated = "Рівень " .. lvl .. " (" .. transFaction .. ")"
                    end
                end
            end

            if not translated then
                local lvl, ctype = cleanText:match("^Level ([%d%?]+) (%w+)$")
                if lvl and ctype then
                    if creatureTypes[ctype] then
                        translated = "Рівень " .. lvl .. " " .. creatureTypes[ctype]
                    end
                end
            end

            if not translated then
                local owner = cleanText:match("^(.+)'s Pet$")
                if owner then
                    local transOwner = ns.GetTranslation and ns.GetTranslation(owner) or owner
                    translated = "Улюбленець " .. transOwner
                end
            end
        end

        if not translated then
            translated = ns.GetTranslation and ns.GetTranslation(text)
        end

        if translated and translated ~= text then
            if cleanText ~= text then
                translated = reassemble(translated, colorPrefix, colorSuffix, isTitle)
            end
            applyLine(fontString, text, translated)
        else
            if cacheCount >= CACHE_MAX then wipe(tooltipCache); cacheCount = 0 end
            tooltipCache[text] = false; cacheCount = cacheCount + 1
        end
    end)
end

local function TranslateUnitTooltip(tooltip)
    if not tooltip then return end
    pcall(function()
        local ok_unit, unit = pcall(tooltip.GetUnit, tooltip)
        if not ok_unit or not unit or unit == "" then return end

        local tname = tooltip.GetName and tooltip:GetName()
        if not tname then return end

        local ok_nl, n = pcall(tooltip.NumLines, tooltip)
        if not ok_nl or not n or n < 1 then return end

        local nameLine = _G[tname .. "TextLeft1"]
        if nameLine then
            translateNameLine(nameLine, unit)
        end

        for i = 2, n do
            local left = _G[tname .. "TextLeft" .. i]
            if left then
                translateUnitTooltipLine(left)
            end
            local right = _G[tname .. "TextRight" .. i]
            if right then
                translateUnitTooltipLine(right)
            end
        end

        local right1 = _G[tname .. "TextRight1"]
        if right1 then
            translateUnitTooltipLine(right1)
        end
    end)
end

ns.TranslateUnitTooltip = TranslateUnitTooltip

function translator:Init()
    pcall(function()
        if TooltipDataProcessor and Enum and Enum.TooltipDataType and Enum.TooltipDataType.Unit then
            TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Unit, function(tooltip)
                TranslateUnitTooltip(tooltip)
            end)
        end
    end)

    pcall(function()
        if GameTooltip then
            GameTooltip:HookScript("OnTooltipSetUnit", function(self)
                C_Timer.After(0, function()
                    TranslateUnitTooltip(self)
                end)
            end)
        end
    end)

    pcall(function()
        if GameTooltip then
            GameTooltip:HookScript("OnShow", function(self)
                local ok_unit, unit = pcall(self.GetUnit, self)
                if ok_unit and unit and unit ~= "" then
                    C_Timer.After(0.01, function()
                        TranslateUnitTooltip(self)
                    end)
                end
            end)
        end
    end)
end
