local _, ns = ...
local L = ns.L or {}

local UIStatusRows = {}
ns.UIStatusRows = UIStatusRows

local BACKDROP_TEMPLATE = BackdropTemplateMixin and "BackdropTemplate" or nil

local UIData = ns.UIData or {}
local PREMIUM = UIData.PREMIUM or {}
local THEME = UIData.THEME or {}
local STATUS_COLORS = UIData.STATUS_COLORS or {}
local WEEKLY_STATUS_ROW_HEIGHT = UIData.WEEKLY_STATUS_ROW_HEIGHT or 34
local WEEKLY_STATUS_BADGE_SIZE = UIData.WEEKLY_STATUS_BADGE_SIZE or 22
local PROFESSION_STATUS_BADGE_TEXTURES = UIData.PROFESSION_STATUS_BADGE_TEXTURES or {}
local PROFESSION_SKILL_LINE_TO_KEY = (ns.Data and ns.Data.PROFESSION_SKILL_LINE_TO_KEY) or {}
local PROFESSION_BADGE_NAME_PATTERNS = {
    alchemy = { "alchemy", "alchemie" },
    blacksmithing = { "blacksmith", "schmied" },
    enchanting = { "enchant", "verzauber" },
    engineering = { "engineer", "ingenieur" },
    herbalism = { "herbal", "kraut" },
    inscription = { "inscription", "inschrift" },
    jewelcrafting = { "jewel", "juwel" },
    leatherworking = { "leather", "leder" },
    mining = { "mining", "bergbau" },
    skinning = { "skinning", "kurschn" },
    tailoring = { "tailor", "schneider", "schneid" },
}

local function createLabel(parent, fontObject, justify)
    local text = parent:CreateFontString(nil, "OVERLAY", fontObject)
    text:SetJustifyH(justify or "LEFT")
    text:SetJustifyV("MIDDLE")
    return text
end

local function setTextureColor(texture, color, alpha)
    if not texture or type(color) ~= "table" then
        return
    end

    texture:SetVertexColor(color[1], color[2], color[3], alpha == nil and 1 or alpha)
end

local function getWeeklyStatusText(entry)
    if not entry then
        return ""
    end

    if type(entry.text) == "string" and entry.text ~= "" then
        return entry.text
    end

    if entry.completed then
        return L.STATUS_DONE or "Done"
    end

    if entry.status == "turnin" or entry.turnInQuestID then
        return L.STATUS_TURNIN or "Turn in"
    end

    if entry.seen then
        return L.STATUS_OPEN or "Accepted"
    end

    return L.STATUS_MISSING or "Accept"
end

local function normalizeProfessionBadgeKey(text)
    local value = string.lower(tostring(text or ""))
    value = value:gsub("\195\132", "a")
    value = value:gsub("\195\164", "a")
    value = value:gsub("\195\150", "o")
    value = value:gsub("\195\182", "o")
    value = value:gsub("\195\156", "u")
    value = value:gsub("\195\188", "u")
    value = value:gsub("\195\159", "ss")
    value = value:gsub("[^%w]+", "")
    return value
end

local function getProfessionStatusBadgeTexture(entry)
    if type(entry) ~= "table" then
        return nil
    end

    local professionKey = type(entry.professionKey) == "string" and entry.professionKey or nil
    local skillLineID = tonumber(entry.skillLineID)
    if (not professionKey) and skillLineID then
        professionKey = PROFESSION_SKILL_LINE_TO_KEY[skillLineID]
    end

    if professionKey and PROFESSION_STATUS_BADGE_TEXTURES[professionKey] then
        return PROFESSION_STATUS_BADGE_TEXTURES[professionKey]
    end

    local nameKey = normalizeProfessionBadgeKey(entry.professionName or entry.name or entry.label)
    for key, patterns in pairs(PROFESSION_BADGE_NAME_PATTERNS) do
        for _, pattern in ipairs(patterns) do
            if nameKey:find(normalizeProfessionBadgeKey(pattern), 1, true) and PROFESSION_STATUS_BADGE_TEXTURES[key] then
                return PROFESSION_STATUS_BADGE_TEXTURES[key]
            end
        end
    end

    return nil
end

local function getWeeklyCustomStatusBadgeVisual(entry)
    if type(entry) ~= "table" then
        return nil
    end

    if entry.statusBadgeFullTexture then
        return {
            texture = entry.statusBadgeFullTexture,
            texCoord = entry.statusBadgeTexCoord,
        }
    end

    if entry.key == "saltherils_favor" and PREMIUM.statusBadgeSaltherilFavor then
        return {
            texture = PREMIUM.statusBadgeSaltherilFavor,
        }
    end

    if entry.statusBadgeTexture then
        return {
            texture = entry.statusBadgeTexture,
            texCoord = entry.statusBadgeTexCoord or { 0.08, 0.92, 0.08, 0.92 },
            customIcon = true,
        }
    end

    local currencyID = tonumber(entry.statusBadgeCurrencyID)
    if currencyID and C_CurrencyInfo and type(C_CurrencyInfo.GetCurrencyInfo) == "function" then
        local info = C_CurrencyInfo.GetCurrencyInfo(currencyID)
        if info and info.iconFileID then
            return {
                texture = info.iconFileID,
                texCoord = { 0.08, 0.92, 0.08, 0.92 },
                customIcon = true,
            }
        end
    end

    local itemID = tonumber(entry.statusBadgeItemID)
    if itemID and C_Item and type(C_Item.GetItemIconByID) == "function" then
        local icon = C_Item.GetItemIconByID(itemID)
        if icon then
            return {
                texture = icon,
                texCoord = { 0.08, 0.92, 0.08, 0.92 },
                customIcon = true,
            }
        end
    end

    if itemID and C_Item and type(C_Item.RequestLoadItemDataByID) == "function" then
        pcall(C_Item.RequestLoadItemDataByID, itemID)
    end

    return nil
end

local function getWeeklyStatusBadgeVisual(status, entry)
    local customVisual = getWeeklyCustomStatusBadgeVisual(entry)
    if customVisual then
        return customVisual
    end

    if status == "complete" then
        return {
            texture = PREMIUM.statusBadgeComplete,
        }
    end

    if status == "missing" then
        return {
            texture = PREMIUM.statusBadgeMissing,
        }
    end

    if status == "turnin" then
        return {
            texture = PREMIUM.statusBadgeTurnin,
        }
    end

    if status == "repeatable" then
        return {
            texture = PREMIUM.statusBadgeRepeatable,
        }
    end

    if status == "locked" then
        return {
            texture = PREMIUM.statusBadgeLocked,
            alpha = 0.78,
        }
    end

    if status == "failed" then
        return {
            texture = PREMIUM.statusBadgeFailed,
        }
    end

    if status == "warning" then
        return {
            texture = PREMIUM.statusBadgeWarning,
        }
    end

    if status == "unknown" then
        return {
            texture = PREMIUM.statusBadgeUnknown,
        }
    end

    if status == "pending" then
        return {
            texture = PREMIUM.statusBadgePending,
        }
    end

    return {
        texture = PREMIUM.statusBadgeOpen,
    }
end

local function applyWeeklyStatusBadge(row, status, entry)
    if not row or not row.statusBadge then
        return
    end

    local visual = getWeeklyStatusBadgeVisual(status, entry)
    if visual.customIcon and row.statusBadgeFrame then
        row.statusBadgeFrame:SetTexture(PREMIUM.statusBadgeFrame or PREMIUM.statusBadgeOpen)
        row.statusBadgeFrame:SetTexCoord(0, 1, 0, 1)
        row.statusBadgeFrame:SetVertexColor(1, 1, 1, visual.frameAlpha or 1)
        row.statusBadgeFrame:Show()
        row.statusBadge:ClearAllPoints()
        row.statusBadge:SetSize(WEEKLY_STATUS_BADGE_SIZE - 14, WEEKLY_STATUS_BADGE_SIZE - 14)
        row.statusBadge:SetPoint("CENTER", row.statusBadgeFrame, "CENTER", 0, 0)
    else
        if row.statusBadgeFrame then
            row.statusBadgeFrame:Hide()
        end
        row.statusBadge:ClearAllPoints()
        row.statusBadge:SetSize(WEEKLY_STATUS_BADGE_SIZE, WEEKLY_STATUS_BADGE_SIZE)
        row.statusBadge:SetPoint("CENTER", row.statusBadgeFrame or row, "CENTER", 0, 0)
    end
    row.statusBadge:SetTexture(visual.texture or PREMIUM.statusBadgeOpen)
    if visual.texCoord then
        row.statusBadge:SetTexCoord(visual.texCoord[1], visual.texCoord[2], visual.texCoord[3], visual.texCoord[4])
    else
        row.statusBadge:SetTexCoord(0, 1, 0, 1)
    end
    row.statusBadge:SetVertexColor(1, 1, 1, visual.alpha or 1)
    row.statusBadge:Show()
end

local function createWeeklyStatusRow(parent)
    local row = CreateFrame("Frame", nil, parent, BACKDROP_TEMPLATE)
    row:SetHeight(WEEKLY_STATUS_ROW_HEIGHT)
    row:SetFrameLevel((parent:GetFrameLevel() or 1) + 2)

    if row.SetBackdrop then
        row:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            tile = false,
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        row:SetBackdropColor(THEME.metalDeep[1], THEME.metalDeep[2], THEME.metalDeep[3], 0.96)
        row:SetBackdropBorderColor(THEME.goldDim[1], THEME.goldDim[2], THEME.goldDim[3], 0.38)
    end

    row.bg = row:CreateTexture(nil, "BACKGROUND")
    row.bg:SetAllPoints()
    row.bg:SetTexture(PREMIUM.row)
    row.bg:SetTexCoord(0.022, 0.978, 0, 1)
    setTextureColor(row.bg, { 1, 1, 1 }, 0.98)

    row.fill = row:CreateTexture(nil, "BACKGROUND")
    row.fill:SetAllPoints()
    row.fill:SetTexture("Interface\\Buttons\\WHITE8X8")
    row.fill:SetColorTexture(THEME.metalInset[1], THEME.metalInset[2], THEME.metalInset[3], 0.04)

    row.hover = row:CreateTexture(nil, "BACKGROUND", nil, 1)
    row.hover:SetAllPoints()
    row.hover:SetTexture("Interface\\Buttons\\WHITE8X8")
    row.hover:SetColorTexture(THEME.gold[1], THEME.gold[2], THEME.gold[3], 0.10)
    row.hover:SetAlpha(0)

    row.statusLine = row:CreateTexture(nil, "ARTWORK")
    row.statusLine:SetPoint("TOPLEFT", 4, -4)
    row.statusLine:SetPoint("BOTTOMLEFT", 4, 4)
    row.statusLine:SetWidth(2)
    row.statusLine:SetColorTexture(1, 1, 1, 0.8)

    row.label = createLabel(row, "GameFontHighlightSmall", "LEFT")
    row.label:SetPoint("LEFT", 14, 0)
    row.label:SetTextColor(THEME.parchment[1], THEME.parchment[2], THEME.parchment[3], 1)

    row.statusBadgeFrame = row:CreateTexture(nil, "ARTWORK", nil, 2)
    row.statusBadgeFrame:SetSize(WEEKLY_STATUS_BADGE_SIZE, WEEKLY_STATUS_BADGE_SIZE)
    row.statusBadgeFrame:SetPoint("RIGHT", -10, 0)
    row.statusBadgeFrame:Hide()

    row.statusBadge = row:CreateTexture(nil, "ARTWORK", nil, 1)
    row.statusBadge:SetSize(WEEKLY_STATUS_BADGE_SIZE, WEEKLY_STATUS_BADGE_SIZE)
    row.statusBadge:SetPoint("CENTER", row.statusBadgeFrame, "CENTER", 0, 0)

    row.value = createLabel(row, "GameFontNormalSmall", "RIGHT")
    row.value:SetPoint("RIGHT", row.statusBadgeFrame, "LEFT", -8, 0)
    row.value:SetWidth(92)
    row.value:SetTextColor(THEME.parchment[1], THEME.parchment[2], THEME.parchment[3], 0.92)

    row.label:SetPoint("RIGHT", row.value, "LEFT", -12, 0)

    row.tooltipTitle = nil
    row.tooltipLines = nil

    row.hitbox = CreateFrame("Button", nil, row)
    row.hitbox:SetAllPoints()
    row.hitbox:SetFrameLevel((row:GetFrameLevel() or 1) + 1)
    row.hitbox:SetScript("OnEnter", function()
        row.hover:SetAlpha(1)
        if row.tooltipTitle or (row.tooltipLines and #row.tooltipLines > 0) then
            GameTooltip:SetOwner(row.hitbox, "ANCHOR_CURSOR_RIGHT")
            if row.tooltipTitle and row.tooltipTitle ~= "" then
                GameTooltip:AddLine(row.tooltipTitle, 1, 0.82, 0.18, true)
            end
            for _, line in ipairs(row.tooltipLines or {}) do
                if type(line) == "string" and line ~= "" then
                    GameTooltip:AddLine(line, 0.92, 0.92, 0.92, true)
                end
            end
            GameTooltip:Show()
        end
    end)
    row.hitbox:SetScript("OnLeave", function()
        row.hover:SetAlpha(0)
        GameTooltip:Hide()
    end)

    return row
end

local function setWeeklyStatusRow(row, entry, labelOverride)
    if not row then
        return
    end

    if not entry then
        row:Hide()
        return
    end

    local status = entry.status or (entry.completed and "complete" or (entry.seen and "open" or "missing"))
    local color = STATUS_COLORS[status] or STATUS_COLORS.missing
    local valueText = getWeeklyStatusText(entry)
    local labelText = labelOverride
    if type(labelText) ~= "string" then
        labelText = type(entry.label) == "string" and entry.label or ""
    end
    if type(valueText) ~= "string" then
        valueText = tostring(valueText or "")
    end

    row.label:SetText(labelText)
    row.label:SetTextColor(0.94, 0.94, 0.96, 1)
    row.value:SetText(valueText)
    row.value:SetTextColor(color[1], color[2], color[3], 1)
    row.statusLine:SetColorTexture(color[1], color[2], color[3], 0.95)
    if entry.hideStatusBadge then
        row.statusBadge:Hide()
        if row.statusBadgeFrame then
            row.statusBadgeFrame:Hide()
        end
        row.value:ClearAllPoints()
        row.value:SetPoint("RIGHT", -12, 0)
    else
        row.value:ClearAllPoints()
        row.value:SetPoint("RIGHT", row.statusBadgeFrame or row.statusBadge, "LEFT", -8, 0)
        applyWeeklyStatusBadge(row, status, entry)
    end
    row.tooltipTitle = entry.tooltipTitle
    row.tooltipLines = entry.tooltipLines
    if row.hitbox then
        row.hitbox:SetScript("OnClick", nil)
    end
    row:Show()
end

local function setStatusRowWithoutBadge(row, entry, labelOverride)
    if type(entry) ~= "table" then
        setWeeklyStatusRow(row, entry, labelOverride)
        return
    end

    local badgeFreeEntry = {}
    for key, value in pairs(entry) do
        badgeFreeEntry[key] = value
    end
    badgeFreeEntry.hideStatusBadge = true
    setWeeklyStatusRow(row, badgeFreeEntry, labelOverride)
end

local function setHousingSidebarStatusRow(row, entry, labelOverride)
    setStatusRowWithoutBadge(row, entry, labelOverride)
    if not row or not row:IsShown() then
        return
    end

    if row.value then
        row.value:SetWidth(78)
        row.value:ClearAllPoints()
        row.value:SetPoint("RIGHT", -10, 0)
        row.value:SetJustifyH("RIGHT")
        if row.value.SetWordWrap then
            row.value:SetWordWrap(false)
        end
        if row.value.SetMaxLines then
            row.value:SetMaxLines(1)
        end
    end

    if row.label then
        row.label:ClearAllPoints()
        row.label:SetPoint("LEFT", 14, 0)
        row.label:SetPoint("RIGHT", row.value, "LEFT", -8, 0)
        row.label:SetJustifyH("LEFT")
        if row.label.SetWordWrap then
            row.label:SetWordWrap(false)
        end
        if row.label.SetMaxLines then
            row.label:SetMaxLines(1)
        end
    end
end

UIStatusRows.GetWeeklyStatusText = getWeeklyStatusText
UIStatusRows.GetProfessionStatusBadgeTexture = getProfessionStatusBadgeTexture
UIStatusRows.ApplyWeeklyStatusBadge = applyWeeklyStatusBadge
UIStatusRows.CreateWeeklyStatusRow = createWeeklyStatusRow
UIStatusRows.SetWeeklyStatusRow = setWeeklyStatusRow
UIStatusRows.SetStatusRowWithoutBadge = setStatusRowWithoutBadge
UIStatusRows.SetHousingSidebarStatusRow = setHousingSidebarStatusRow
