-- matcher.lua
local _, ns = ...
local Matcher = {}
ns.Matcher = Matcher

local function normalize(text)
  --text = text:gsub("[%p]", " ") -- базовая очистка пунктуации (оставь нужное)
  return text
end

-- Возвращает количество символов в строке (а не байтов)
local function utf8len(str)
    local _, count = string.gsub(str, "[^\128-\193]", "")
    return count
end

-- Возвращает подстроку по символам, а не байтам
local function utf8sub(str, i, j)
    j = j or utf8len(str)
    if i < 1 then i = 1 end
    if j < i then return "" end

    local startByte = 1
    local currentIndex = 0
    for pos = 1, #str do
        local byte = string.byte(str, pos)
        if byte < 128 or byte >= 192 then
            currentIndex = currentIndex + 1
            if currentIndex == i then
                startByte = pos
            end
            if currentIndex == j + 1 then
                return string.sub(str, startByte, pos - 1)
            end
        end
    end
    return string.sub(str, startByte)
end

local utf8upper_map = {
  ["а"]="А", ["б"]="Б", ["в"]="В", ["г"]="Г", ["д"]="Д", ["е"]="Е", ["ё"]="Ё",
  ["ж"]="Ж", ["з"]="З", ["и"]="И", ["й"]="Й", ["к"]="К", ["л"]="Л", ["м"]="М",
  ["н"]="Н", ["о"]="О", ["п"]="П", ["р"]="Р", ["с"]="С", ["т"]="Т", ["у"]="У",
  ["ф"]="Ф", ["х"]="Х", ["ц"]="Ц", ["ч"]="Ч", ["ш"]="Ш", ["щ"]="Щ", ["ъ"]="Ъ",
  ["ы"]="Ы", ["ь"]="Ь", ["э"]="Э", ["ю"]="Ю", ["я"]="Я",
}

local function utf8upper(ch)
  return utf8upper_map[ch] or string.upper(ch)
end

local function ucfirst(str)
  local first = utf8sub(str, 1, 1)
  local rest = utf8sub(str, 2)
  return utf8upper(first) .. (rest or "")
end

local function restoreCaps(srcText, translated)
  -- Простая капитализация: если исходное начиналось с заглавной, поднимем первую букву.
  if srcText:match("^[%u]") then
    -- Поднимаем первую букву перевода
    translated = ucfirst(translated);

  end
  return translated
end

-- Проверка на числа
local function has_digits_only(word)
    return tonumber(word) ~= nil
end

local function stripPunct(token)
  local prefix, core, suffix = token:match("^(%p*)(%w+)(%p*)$")
  return prefix, core, suffix
end

-- Фразы первичны
function Matcher:TranslatePhrases(text, dict)
  local out = text
  for _, entry in ipairs(dict.phraseList) do
    local pat = entry.pattern
    if entry.isFn then
      out = out:gsub(pat, function(...)
        local res = entry.replace(...)
        return res or ...
      end)
    else
      out = out:gsub(pat, entry.replace)
    end
  end
  return out
end


function Matcher:TranslateWords(text, dict)
  local out = {}
  for token in text:gmatch("%S+") do
    -- отделяем "чистое слово" от пунктуации
    local prefix, core, suffix = stripPunct(token)
    if core then
      local tr = dict.wordMap[core:lower()]

      if not tr then
        if has_digits_only() == false then
          MagicTranslatorDB.missing = MagicTranslatorDB.missing or {}
          --print("[Missing][Added]- " .. core:lower())
          MagicTranslatorDB.missing[core:lower()] = (MagicTranslatorDB.missing[core:lower()] or 0) + 1
        end
      else
        if MagicTranslatorDB.missing[core:lower()] then
          MagicTranslatorDB.missing[core:lower()] = nil
          --print("[Missing][Removed] - " .. core:lower())
        end
      end

      table.insert(out, (prefix or "") .. (tr or core) .. (suffix or ""))
    else
      table.insert(out, token) -- если не слово, оставляем как есть
    end
  end
  return table.concat(out, " ")
end

function Matcher:Translate(text, mode)
  local dict = ns.Dictionary:GetIndex()
  if not dict or not dict.src then return text end

  local original = text
  local normalized = normalize(text)
  normalized = ns.VerbTense:Expand_contractions(normalized)
  
  local result = normalized
  if mode == "phrases-first" then
    result = Matcher:TranslatePhrases(result, dict)
    result = Matcher:TranslateWords(result, dict)
  elseif mode == "words-only" then
    result = Matcher:TranslateWords(result, dict)
  else -- transparent: только подсветка/никакой перевода
    result = normalized
  end

  result = restoreCaps(original, result)
  return result
end