local MAJOR, MINOR = "LibMatic-CustomMedia-1.0", 2
assert(LibStub, MAJOR .. " requires LibStub")
local lib = LibStub:NewLibrary(MAJOR, MINOR)
if not lib then return end

local CreateFrame = CreateFrame
local UIParent = UIParent
local PlaySoundFile = PlaySoundFile
local StopSound = StopSound
local wipe = wipe or table.wipe
local floor = math.floor

local SOUND_FOLDER = "CustomSounds"
local FONT_FOLDER = "CustomFonts"
local SOUND_PREFIX = "Sound"
local FONT_PREFIX = "Font"
local SOUND_EXTS = { "ogg", "mp3" }
local FONT_EXTS = { "ttf", "otf" }
local DEFAULT_COUNT = 10
local PROBE_FONT_SIZE = 12
local RESET_FONT = "Fonts\\FRIZQT__.TTF"

lib.profiles = lib.profiles or {}

local function fetchLib(name)
    return LibStub and LibStub(name, true)
end

local function ensureProbeFont()
    if lib.probeFont then return lib.probeFont end
    local frame = CreateFrame("Frame", nil, UIParent)
    frame:Hide()
    lib.probeFont = frame:CreateFontString(nil, "ARTWORK")
    return lib.probeFont
end

local function fontFileLoads(path)
    local fs = ensureProbeFont()
    fs:SetFont(RESET_FONT, PROBE_FONT_SIZE, "")
    local baseline = fs:GetFont()
    local ok = pcall(fs.SetFont, fs, path, PROBE_FONT_SIZE, "")
    if not ok then return false end
    local got = fs:GetFont()
    return got ~= nil and got ~= baseline
end

local function soundFileLoads(path)
    if not PlaySoundFile then return false end
    local willPlay, handle = PlaySoundFile(path, "Master")
    if willPlay and handle and StopSound then
        StopSound(handle, 0)
    end
    return willPlay and true or false
end

local function buildPath(addon, folder, prefix, index, ext)
    return "Interface\\AddOns\\" .. addon .. "\\" .. folder .. "\\" .. prefix .. index .. "." .. ext
end

local function resolveFont(addon, index)
    for _, ext in ipairs(FONT_EXTS) do
        local path = buildPath(addon, FONT_FOLDER, FONT_PREFIX, index, ext)
        if fontFileLoads(path) then return path end
    end
    return nil
end

local function resolveSound(addon, index)
    for _, ext in ipairs(SOUND_EXTS) do
        local path = buildPath(addon, SOUND_FOLDER, SOUND_PREFIX, index, ext)
        if soundFileLoads(path) then return path end
    end
    return nil
end

local function lsmName(addon, kind, index)
    return addon .. " Custom " .. kind .. " " .. index
end

local function applyFonts(profile)
    local LSM = fetchLib("LibSharedMedia-3.0")
    wipe(profile.registered.fonts)
    if not LSM then return 0 end
    local found = 0
    for index = 1, profile.fonts do
        local path = resolveFont(profile.addon, index)
        if path then
            local name = lsmName(profile.addon, "Font", index)
            LSM:Register("font", name, path)
            profile.registered.fonts[index] = name
            found = found + 1
        end
    end
    return found
end

local function applySoundsFromCache(profile)
    local LSM = fetchLib("LibSharedMedia-3.0")
    wipe(profile.registered.sounds)
    if not LSM then return 0 end
    local found = 0
    for index, path in pairs(profile.cache) do
        if type(path) == "string" then
            local name = lsmName(profile.addon, "Sound", index)
            LSM:Register("sound", name, path)
            profile.registered.sounds[index] = name
            found = found + 1
        end
    end
    return found
end

local function applySoundScan(profile)
    local LSM = fetchLib("LibSharedMedia-3.0")
    wipe(profile.cache)
    wipe(profile.registered.sounds)
    if not LSM then return 0 end
    local found = 0
    for index = 1, profile.sounds do
        local path = resolveSound(profile.addon, index)
        if path then
            local name = lsmName(profile.addon, "Sound", index)
            profile.cache[index] = path
            LSM:Register("sound", name, path)
            profile.registered.sounds[index] = name
            found = found + 1
        end
    end
    return found
end

local function normalizeCount(value)
    if type(value) ~= "number" then
        return DEFAULT_COUNT
    end
    local count = floor(value)
    if count > 0 then
        return count
    end
    return DEFAULT_COUNT
end

function lib:Register(opts)
    opts = opts or {}
    assert(type(opts.addon) == "string", MAJOR .. ":Register requires opts.addon")
    local profile = {
        addon = opts.addon,
        sounds = normalizeCount(opts.sounds),
        fonts = normalizeCount(opts.fonts),
        cache = opts.soundCache or {},
        registered = { sounds = {}, fonts = {} },
    }
    lib.profiles[opts.addon] = profile
    local fontsFound = applyFonts(profile)
    local soundsFound = applySoundsFromCache(profile)
    return soundsFound, fontsFound
end

function lib:Scan(addon)
    local profile = lib.profiles[addon]
    if not profile then return 0, 0 end
    local soundsFound = applySoundScan(profile)
    local fontsFound = applyFonts(profile)
    return soundsFound, fontsFound
end

function lib:GetRegistered(addon)
    local profile = lib.profiles[addon]
    if not profile then return { sounds = {}, fonts = {} } end
    return profile.registered
end
