-- ============================================================
-- Asylum Compagnon — GearCompassDatabase.lua
-- Migration ciblée et paramètres persistants minimaux de l'export GearCompass.
-- ============================================================

local _, NS = ...

local DB = {}
NS.GearCompassDB = DB

local DEFAULT_SETTINGS = {
    includeEquipped = true,
    includeBags = true,
    includeNonEquippable = false,
}
DB.DEFAULT_SETTINGS = DEFAULT_SETTINGS

local debugEnabled = false
local LEGACY_DB_KEY = "tank" .. "gear"

local function IsCurrentExport(value)
    if type(value) ~= "string" then return false end
    -- 0.43.0 utilisait GetCombatRating et 0.43.1 ne certifiait pas explicitement
    -- le périmètre. Tout payload contenant character_stats sans les métadonnées
    -- canoniques 0.43.4 doit être régénéré. Les exports 0.42 sans ce bloc restent
    -- acceptés pour ne pas effacer un ancien export compact valide.
    local hasCharacterStats = value:find('"character_stats":', 1, true) ~= nil
    local hasPermanentSource = value:find(
        '"character_stats_source":"equipped_items_and_gems"', 1, true) ~= nil
    local hasCanonicalMeta = value:find('"character_stats_meta":{', 1, true) ~= nil
        and value:find('"method":"equipped_items_and_gems"', 1, true) ~= nil
        and value:find('"includes_enchantments":false', 1, true) ~= nil
        and value:find('"includes_temporary_auras":false', 1, true) ~= nil
        and value:find('"includes_gems":', 1, true) ~= nil
        and value:find('"complete":', 1, true) ~= nil
        and value:find('"unresolved_gems":', 1, true) ~= nil
    return (not hasCharacterStats or (hasPermanentSource and hasCanonicalMeta))
        and value:find('"export_type":"gearcompass"', 1, true) ~= nil
        and value:find('"schema_version":1', 1, true) ~= nil
        and value:find('"addon":', 1, true) ~= nil
        and value:find('"character":', 1, true) ~= nil
        and value:find('"errors":', 1, true) ~= nil
        and value:find('"items":', 1, true) ~= nil
        and value:find('"game":', 1, true) == nil
        and value:find('"generated_at":', 1, true) == nil
        and value:find('"scan":', 1, true) == nil
        and value:find('"adjustments":', 1, true) == nil
end
DB.IsCurrentExport = IsCurrentExport

function DB.Migrate(root)
    if type(root) ~= "table" then return nil, "DB_ROOT_MISSING" end
    -- Reprend une seule fois les préférences enregistrées sous l'ancien nom,
    -- puis supprime cette clé afin que seules les données GearCompass subsistent.
    if type(root.gearcompass) ~= "table" then
        root.gearcompass = type(root[LEGACY_DB_KEY]) == "table" and root[LEGACY_DB_KEY] or {}
    end
    root[LEGACY_DB_KEY] = nil
    local gearcompass = root.gearcompass

    if type(gearcompass.settings) ~= "table" then gearcompass.settings = {} end
    for key, value in pairs(DEFAULT_SETTINGS) do
        if gearcompass.settings[key] == nil then gearcompass.settings[key] = value end
    end
    for key in pairs(gearcompass.settings) do
        if DEFAULT_SETTINGS[key] == nil then gearcompass.settings[key] = nil end
    end

    -- Les exports riches antérieurs ne correspondent plus au contrat compact :
    -- ne jamais les réafficher comme s'ils venaient de la version actuelle.
    if gearcompass.lastExport ~= nil and not IsCurrentExport(gearcompass.lastExport) then
        gearcompass.lastExport = nil
    end

    -- Périmètre persistant strict : settings + lastExport, rien d'autre.
    for key in pairs(gearcompass) do
        if key ~= "settings" and key ~= "lastExport" then gearcompass[key] = nil end
    end
    return gearcompass
end

function DB.Init()
    if not NS.db then return nil end
    return DB.Migrate(NS.db)
end

function DB.Get()
    return (NS.db and NS.db.gearcompass) or DB.Init()
end

function DB.GetSettings()
    local data = DB.Get()
    return data and data.settings or DEFAULT_SETTINGS
end

function DB.IsDebugEnabled()
    return debugEnabled
end

function DB.ToggleDebug()
    debugEnabled = not debugEnabled
    return debugEnabled
end

function NS.GearCompassDebug(message, ...)
    if not debugEnabled then return end
    local text = tostring(message or "")
    if select("#", ...) > 0 then
        local ok, formatted = pcall(string.format, text, ...)
        if ok then text = formatted end
    end
    if NS.Msg then NS.Msg("|cff8b8fa3[GearCompass]|r " .. text) end
end

function DB.SelfTestMigration()
    local oldExport = '{"addon":{},"character":{},"errors":[],"export_type":"gearcompass","game":{},"items":[],"scan":{},"schema_version":1}'
    -- Contrat compact 0.42 : l'absence des ajouts 0.43 doit rester valide.
    local compact042 = '{"addon":{"name":"AsylumCompagnon","version":"0.42.0"},"character":{},"errors":[],"export_type":"gearcompass","items":[],"schema_version":1}'
    local live0430 = '{"addon":{"name":"AsylumCompagnon","version":"0.43.0"},"character":{},"character_stats":{"critical_strike":1,"haste":2,"mastery":3,"versatility":4},"errors":[],"export_type":"gearcompass","items":[],"schema_version":1}'
    local permanent0431 = '{"addon":{"name":"AsylumCompagnon","version":"0.43.1"},"character":{},"character_stats":{"critical_strike":1,"haste":2,"mastery":3,"versatility":4},"character_stats_source":"equipped_items_and_gems","errors":[],"export_type":"gearcompass","items":[{"enchantment":{"applicable":true,"enchant_id":1,"name":null,"spell_id":null}}],"schema_version":1}'
    local canonical0432 = '{"addon":{"name":"AsylumCompagnon","version":"0.43.2"},"character":{},"character_stats":{"critical_strike":1,"haste":2,"mastery":3,"versatility":4},"character_stats_meta":{"complete":true,"includes_enchantments":false,"includes_gems":true,"includes_temporary_auras":false,"method":"equipped_items_and_gems"},"character_stats_source":"equipped_items_and_gems","errors":[],"export_type":"gearcompass","items":[{"enchantment":{"applicable":true,"enchant_id":1,"name":null,"spell_id":null}}],"schema_version":1}'
    local incomplete0432 = '{"addon":{"name":"AsylumCompagnon","version":"0.43.2"},"character":{},"character_stats":{"critical_strike":null,"haste":null,"mastery":null,"versatility":null},"character_stats_meta":{"complete":false,"includes_enchantments":false,"includes_gems":false,"includes_temporary_auras":false,"method":"equipped_items_and_gems"},"character_stats_source":"equipped_items_and_gems","errors":[],"export_type":"gearcompass","items":[],"schema_version":1}'
    local canonical0434 = '{"addon":{"name":"AsylumCompagnon","version":"0.43.4"},"character":{},"character_stats":{"critical_strike":1,"haste":2,"mastery":3,"versatility":4},"character_stats_meta":{"complete":true,"includes_enchantments":false,"includes_gems":true,"includes_temporary_auras":false,"method":"equipped_items_and_gems","unresolved_gems":[]},"character_stats_source":"equipped_items_and_gems","errors":[],"export_type":"gearcompass","items":[],"schema_version":1}'
    local fake = {}
    fake[LEGACY_DB_KEY] = {
        settings = { includeBags = false, includeBank = true, unknown = true },
        bankCache = {},
        lastExport = oldExport,
        lastExportAt = 123,
        lastExportSummary = {},
        storageVersion = 2,
        debug = true,
    }
    local data = DB.Migrate(fake)
    local exactRoot, exactSettings = true, true
    for key in pairs(data or {}) do
        if key ~= "settings" and key ~= "lastExport" then exactRoot = false end
    end
    for key in pairs(data and data.settings or {}) do
        if DEFAULT_SETTINGS[key] == nil then exactSettings = false end
    end
    local ok = data and data.settings.includeBags == false
        and data.settings.includeEquipped == true
        and data.settings.includeBank == nil
        and data.bankCache == nil
        and data.lastExport == nil
        and data.lastExportSummary == nil
        and fake[LEGACY_DB_KEY] == nil
        and fake.gearcompass == data
        and exactRoot and exactSettings
    data.lastExport = compact042
    DB.Migrate(fake)
    ok = ok and data.lastExport == compact042 and IsCurrentExport(compact042)
    data.lastExport = live0430
    DB.Migrate(fake)
    ok = ok and data.lastExport == nil and not IsCurrentExport(live0430)
    data.lastExport = permanent0431
    DB.Migrate(fake)
    ok = ok and data.lastExport == nil and not IsCurrentExport(permanent0431)
    data.lastExport = canonical0432
    DB.Migrate(fake)
    ok = ok and data.lastExport == nil and not IsCurrentExport(canonical0432)
    data.lastExport = incomplete0432
    DB.Migrate(fake)
    ok = ok and data.lastExport == nil and not IsCurrentExport(incomplete0432)
    data.lastExport = canonical0434
    DB.Migrate(fake)
    ok = ok and data.lastExport == canonical0434 and IsCurrentExport(canonical0434)
    return not not ok, fake
end
