SFrames.Focus = {}

local function Trim(text)
    if type(text) ~= "string" then return "" end
    text = string.gsub(text, "^%s+", "")
    text = string.gsub(text, "%s+$", "")
    return text
end

function SFrames.Focus:EnsureDB()
    if not SFramesDB then SFramesDB = {} end
    if not SFramesDB.Focus then SFramesDB.Focus = {} end
    return SFramesDB.Focus
end

function SFrames.Focus:Initialize()
    self:EnsureDB()
end

function SFrames.Focus:GetFocusName()
    if UnitExists and UnitExists("focus") and UnitName then
        local name = UnitName("focus")
        if name and name ~= "" then
            return name
        end
    end

    local db = self:EnsureDB()
    if db.name and db.name ~= "" then
        return db.name
    end
    return nil
end

function SFrames.Focus:SetFromTarget()
    if not UnitExists or not UnitExists("target") then
        return false, "NO_TARGET"
    end

    local name = UnitName and UnitName("target")
    if not name or name == "" then
        return false, "INVALID_TARGET"
    end

    local db = self:EnsureDB()
    db.name = name
    db.level = UnitLevel and UnitLevel("target") or nil
    local _, classToken = UnitClass and UnitClass("target")
    db.class = classToken

    local usedNative = false
    if FocusUnit then
        local ok = pcall(function() FocusUnit("target") end)
        if not ok then
            ok = pcall(function() FocusUnit() end)
        end
        if ok and UnitExists and UnitExists("focus") then
            usedNative = true
        end
    end

    return true, name, usedNative
end

function SFrames.Focus:Clear()
    if ClearFocus then
        pcall(ClearFocus)
    end

    local db = self:EnsureDB()
    db.name = nil
    db.level = nil
    db.class = nil

    return true
end

function SFrames.Focus:Target()
    if UnitExists and UnitExists("focus") then
        TargetUnit("focus")
        return true, "NATIVE"
    end

    local name = self:GetFocusName()
    if not name then
        return false, "NO_FOCUS"
    end

    if TargetByName then
        TargetByName(name, true)
    else
        return false, "NO_TARGETBYNAME"
    end

    if UnitExists and UnitExists("target") and UnitName and UnitName("target") == name then
        return true, "NAME"
    end
    return false, "NOT_FOUND"
end

function SFrames.Focus:Cast(spellName)
    local spell = Trim(spellName)
    if spell == "" then
        return false, "NO_SPELL"
    end

    if UnitExists and UnitExists("focus") then
        CastSpellByName(spell)
        if SpellIsTargeting and SpellIsTargeting() then
            SpellTargetUnit("focus")
        end
        if SpellIsTargeting and SpellIsTargeting() then
            SpellStopTargeting()
            return false, "BAD_TARGET"
        end
        return true, "NATIVE"
    end

    local focusName = self:GetFocusName()
    if not focusName then
        return false, "NO_FOCUS"
    end

    local hadTarget = UnitExists and UnitExists("target")
    local prevName = hadTarget and UnitName and UnitName("target") or nil

    local onFocus = false
    if hadTarget and prevName == focusName then
        onFocus = true
    elseif TargetByName then
        TargetByName(focusName, true)
        if UnitExists and UnitExists("target") and UnitName and UnitName("target") == focusName then
            onFocus = true
        end
    end

    if not onFocus then
        return false, "FOCUS_NOT_FOUND"
    end

    CastSpellByName(spell)
    if SpellIsTargeting and SpellIsTargeting() then
        SpellTargetUnit("target")
    end
    if SpellIsTargeting and SpellIsTargeting() then
        SpellStopTargeting()
        if hadTarget and prevName and prevName ~= focusName and TargetLastTarget then
            TargetLastTarget()
        end
        return false, "BAD_TARGET"
    end

    if hadTarget and prevName and prevName ~= focusName and TargetLastTarget then
        TargetLastTarget()
    end
    return true, "NAME"
end

