local _, ns = ...

local Util = ns.Util or {}
local getWeeklyResetInfo = Util.GetWeeklyResetInfo
local VALID_SIDEBAR_SORT_MODES = {
    name = true,
    level = true,
    itemLevel = true,
    priority = true,
}

function ns:EnsureDB()
    if type(VaultloomNextDB) ~= "table" then
        VaultloomNextDB = {}
    end

    local db = VaultloomNextDB
    local currentCharacterKey = self:BuildCharacterKey(UnitName("player"), GetRealmName())
    db.characters = type(db.characters) == "table" and db.characters or {}
    db.ui = type(db.ui) == "table" and db.ui or {}
    db.hiddenCharacters = type(db.hiddenCharacters) == "table" and db.hiddenCharacters or {}
    db.ui.hiddenUtilityResources = type(db.ui.hiddenUtilityResources) == "table" and db.ui.hiddenUtilityResources or {}
    db.ui.newsSeenVersion = type(db.ui.newsSeenVersion) == "string" and db.ui.newsSeenVersion or ""
    db.ui.selectedMainTab = db.ui.selectedMainTab or "vault"
    db.ui.hiddenMainTabs = type(db.ui.hiddenMainTabs) == "table" and db.ui.hiddenMainTabs or {}
    db.ui.selectedSubTabs = type(db.ui.selectedSubTabs) == "table" and db.ui.selectedSubTabs or {}
    db.ui.selectedMidnightRareZoneKey = type(db.ui.selectedMidnightRareZoneKey) == "string" and db.ui.selectedMidnightRareZoneKey or nil
    db.ui.sidebarSortMode = VALID_SIDEBAR_SORT_MODES[db.ui.sidebarSortMode] and db.ui.sidebarSortMode or nil
    db.ui.selectedCharacterKey = db.ui.selectedCharacterKey or currentCharacterKey
    db.ui.scalePercent = math.max(70, math.min(125, tonumber(db.ui.scalePercent) or 100))
    db.ui.opacityPercent = math.max(65, math.min(100, tonumber(db.ui.opacityPercent) or 100))
    db.ui.windowPosition = type(db.ui.windowPosition) == "table" and db.ui.windowPosition or nil
    db.ui.minimap = db.ui.minimap or {}
    db.ui.minimap.hide = db.ui.minimap.hide == true or db.ui.minimap.hidden == true
    db.ui.minimap.hidden = db.ui.minimap.hide == true
    db.ui.minimap.minimapPos = tonumber(db.ui.minimap.minimapPos or db.ui.minimap.angle) or 225
    db.ui.minimap.angle = tonumber(db.ui.minimap.minimapPos) or 225
    db.ui.raidJournal = type(db.ui.raidJournal) == "table" and db.ui.raidJournal or {}
    db.ui.raidJournal.selectedRaidKey = type(db.ui.raidJournal.selectedRaidKey) == "string" and db.ui.raidJournal.selectedRaidKey or "dreamrift"
    db.ui.raidJournal.selectedBossKey = type(db.ui.raidJournal.selectedBossKey) == "string" and db.ui.raidJournal.selectedBossKey or ""
    db.ui.raidJournal.difficultyKey = type(db.ui.raidJournal.difficultyKey) == "string" and db.ui.raidJournal.difficultyKey or "normal"
    db.ui.raidJournal.classFilterMode = type(db.ui.raidJournal.classFilterMode) == "string" and db.ui.raidJournal.classFilterMode or "player"
    db.ui.raidJournal.classFilterKey = type(db.ui.raidJournal.classFilterKey) == "string" and db.ui.raidJournal.classFilterKey
        or ((db.ui.raidJournal.classFilterMode == "all" or db.ui.raidJournal.classFilterMode == "player") and db.ui.raidJournal.classFilterMode or "player")
    db.ui.dungeonJournal = type(db.ui.dungeonJournal) == "table" and db.ui.dungeonJournal or {}
    db.ui.dungeonJournal.selectedRaidKey = type(db.ui.dungeonJournal.selectedRaidKey) == "string" and db.ui.dungeonJournal.selectedRaidKey or ""
    db.ui.dungeonJournal.selectedBossKey = type(db.ui.dungeonJournal.selectedBossKey) == "string" and db.ui.dungeonJournal.selectedBossKey or ""
    db.ui.dungeonJournal.difficultyKey = type(db.ui.dungeonJournal.difficultyKey) == "string" and db.ui.dungeonJournal.difficultyKey or "normal"
    db.ui.dungeonJournal.classFilterMode = type(db.ui.dungeonJournal.classFilterMode) == "string" and db.ui.dungeonJournal.classFilterMode or "player"
    db.ui.dungeonJournal.classFilterKey = type(db.ui.dungeonJournal.classFilterKey) == "string" and db.ui.dungeonJournal.classFilterKey
        or ((db.ui.dungeonJournal.classFilterMode == "all" or db.ui.dungeonJournal.classFilterMode == "player") and db.ui.dungeonJournal.classFilterMode or "player")
    db.raidLootTracker = type(db.raidLootTracker) == "table" and db.raidLootTracker or {}
    db.weeklyMemory = type(db.weeklyMemory) == "table" and db.weeklyMemory or {}
    db.features = type(db.features) == "table" and db.features or {}
    db.renown = type(db.renown) == "table" and db.renown or {}
    if self.EnsureRenownDB then
        self:EnsureRenownDB()
    end
    if self.EnsureCustomTasksDB then
        self:EnsureCustomTasksDB()
    end

    local _, weeklyResetAt = getWeeklyResetInfo()
    local currentWeekKey = tonumber(weeklyResetAt)
    if currentWeekKey and currentWeekKey > 0 then
        currentWeekKey = tostring(currentWeekKey)
        for bucketKey, bucket in pairs(db.weeklyMemory) do
            if type(bucket) ~= "table" then
                db.weeklyMemory[bucketKey] = nil
            else
                for characterKey, weeks in pairs(bucket) do
                    if type(weeks) ~= "table" then
                        bucket[characterKey] = nil
                    else
                        for weekKey in pairs(weeks) do
                            if tostring(weekKey) ~= currentWeekKey then
                                weeks[weekKey] = nil
                            end
                        end

                        if next(weeks) == nil then
                            bucket[characterKey] = nil
                        end
                    end
                end

                if next(bucket) == nil then
                    db.weeklyMemory[bucketKey] = nil
                end
            end
        end
    end

    if type(db.mainCharacterKey) ~= "string" or db.mainCharacterKey == "" then
        local liveDB = self:GetLiveVaultloomDB()
        if liveDB and type(liveDB.mainCharacter) == "string" and liveDB.mainCharacter ~= "" then
            db.mainCharacterKey = liveDB.mainCharacter
        else
            db.mainCharacterKey = self:BuildCharacterKey(UnitName("player"), GetRealmName())
        end
    end

    if not self:IsKnownMainTab(db.ui.selectedMainTab) then
        db.ui.selectedMainTab = "vault"
    end
    for tabKey in pairs(db.ui.hiddenMainTabs) do
        if not self:IsKnownMainTab(tabKey) then
            db.ui.hiddenMainTabs[tabKey] = nil
        end
    end

    for mainTab, defaultSubTab in pairs(self:GetDefaultSubTabs()) do
        db.ui.selectedSubTabs[mainTab] = db.ui.selectedSubTabs[mainTab] or defaultSubTab
    end

    if db.ui.lastLoadedCharacterKey ~= currentCharacterKey then
        db.ui.selectedCharacterKey = currentCharacterKey
        db.ui.selectedMainTab = "vault"
        db.ui.selectedSubTabs.vault = self:GetDefaultSubTab("vault")
    end
    db.ui.lastLoadedCharacterKey = currentCharacterKey
    db.hiddenCharacters[currentCharacterKey] = nil
    self.db = db
    if self.GetVisibleMainTabCount and self:GetVisibleMainTabCount() < 1 then
        db.ui.hiddenMainTabs.vault = nil
    end
    if self.IsMainTabEnabled and not self:IsMainTabEnabled(db.ui.selectedMainTab) then
        db.ui.selectedMainTab = (self.GetFirstVisibleMainTab and self:GetFirstVisibleMainTab()) or "vault"
    end

    for _, character in pairs(db.characters) do
        self:ClearExpiredVaultSnapshot(character)
        self:ClearExpiredPreyState(character)
        self:ClearExpiredDailyPveState(character)
        if self.ClearExpiredMidnightRareState then
            self:ClearExpiredMidnightRareState(character)
        end
        self:ClearExpiredDelvesState(character)
        self:ClearExpiredWorldWeeklyState(character)
        self:ClearExpiredPvpWeeklyState(character)
        self:ClearExpiredProfessionWeeklyState(character)
    end
end

function ns:GetStoredCharacterRecord(key, createIfMissing)
    if not self.db then
        return nil
    end

    self.db.characters = self.db.characters or {}

    if type(key) ~= "string" or key == "" then
        key = self:GetCurrentCharacterInfo().key
    end

    if createIfMissing and type(self.db.characters[key]) ~= "table" then
        self.db.characters[key] = {}
    end

    return self.db.characters[key]
end

function ns:RefreshCurrentCharacterRecord()
    local currentInfo = self:GetCurrentCharacterInfo()

    if type(VaultloomNextDB) ~= "table" then
        VaultloomNextDB = {}
    end
    self.db = type(self.db) == "table" and self.db or VaultloomNextDB
    self.db.characters = type(self.db.characters) == "table" and self.db.characters or {}

    local record = self.db.characters[currentInfo.key]
    if type(record) ~= "table" then
        record = {}
        self.db.characters[currentInfo.key] = record
    end

    record.key = currentInfo.key
    record.name = currentInfo.name
    record.realm = currentInfo.realm
    record.className = currentInfo.className
    record.classFile = select(2, UnitClass("player"))
    record.level = currentInfo.level
    record.itemLevel = self:GetCurrentEquippedItemLevel() or record.itemLevel
    local currentMoney = self:GetCurrentMoney()
    if currentMoney ~= nil and not (currentMoney == 0 and tonumber(record.money) and tonumber(record.money) > 0) then
        record.money = currentMoney
    end
    if self.professionsDirty or type(record.professions) ~= "table" then
        local scannedProfessions = self:ScanCharacterProfessions()
        if #scannedProfessions > 0 or type(record.professions) ~= "table" then
            record.professions = scannedProfessions
        end
        self.professionsDirty = false
    end
    record.lastSeen = time()

    return record
end

function ns:RefreshCurrentCharacterMoneySnapshot(allowZero)
    local currentInfo = self:GetCurrentCharacterInfo()
    local money = self:GetCurrentMoney()
    if money == nil then
        return nil
    end

    if type(VaultloomNextDB) ~= "table" then
        VaultloomNextDB = {}
    end
    self.db = type(self.db) == "table" and self.db or VaultloomNextDB
    self.db.characters = type(self.db.characters) == "table" and self.db.characters or {}

    local record = self.db.characters[currentInfo.key]
    if type(record) ~= "table" then
        record = {}
        self.db.characters[currentInfo.key] = record
    end

    local existingMoney = tonumber(record.money)
    if money == 0 and allowZero ~= true and existingMoney and existingMoney > 0 then
        money = existingMoney
    end

    record.key = currentInfo.key
    record.name = currentInfo.name
    record.realm = currentInfo.realm
    record.className = currentInfo.className
    record.classFile = select(2, UnitClass("player"))
    record.level = currentInfo.level
    record.itemLevel = self:GetCurrentEquippedItemLevel() or record.itemLevel
    record.money = money
    record.lastSeen = time()

    return record
end
