-- bimg_advanced.lua
-- 增强版 BIMG 图像/动画播放库
-- 功能:
-- 1. 支持文件路径、URL 和直接数据播放
-- 2. 支持循环播放
-- 3. 提供播放控制功能
-- 4. 支持多显示器配置
-- 5. 支持自定义终端对象

local bimg = {}

local currentAnimation = nil
local running = false
local httpEnabled = false

-- 检查并启用HTTP功能
if http and http.get then
    httpEnabled = true
end

-- 内部函数：绘制单帧
local function drawFrame(frame, termObj)
    for y, row in ipairs(frame) do
        termObj.setCursorPos(1, y)
        termObj.blit(table.unpack(row))
    end
    if frame.palette then 
        for i = 0, #frame.palette do
            local c = frame.palette[i]
            if type(c) == "table" then 
                termObj.setPaletteColor(2^i, table.unpack(c))
            else 
                termObj.setPaletteColor(2^i, c) 
            end
        end 
    end
end

-- 内部函数：加载图像数据
local function loadImageData(data)
    if type(data) == "string" then
        -- 如果是字符串，尝试反序列化
        local success, result = pcall(textutils.unserialize, data)
        if success then
            return result
        else
            error("Invalid image data: " .. result)
        end
    elseif type(data) == "table" then
        -- 如果是table，直接使用
        return data
    else
        error("Unsupported image data type")
    end
end

-- 从文件加载图像
function bimg.loadFromFile(path)
    local file, err = fs.open(shell.resolve(path), "rb")
    if not file then error("Could not open file: " .. err) end
    local data = file.readAll()
    file.close()
    return loadImageData(data)
end

-- 从URL加载图像
function bimg.loadFromURL(url)
    if not httpEnabled then
        error("HTTP API is not available")
    end
    
    local response = http.get(url)
    if not response then
        error("Failed to fetch from URL: " .. url)
    end
    
    local data = response.readAll()
    response.close()
    return loadImageData(data)
end

-- 内部函数：校准多显示器
local function calibrateMonitors(width, height)
    term.clear()
    term.setCursorPos(1, 1)
    print('This image needs monitors to be calibrated before being displayed.')
    print('Please right-click each monitor in order, from the top left corner')
    print('to the bottom right corner, going right first, then down.')
    
    local monitors = {}
    local names = {}
    
    for y = 1, height do
        monitors[y] = {}
        for x = 1, width do
            local _, oy = term.getCursorPos()
            
            -- 绘制校准界面
            for ly = 1, height do
                term.setCursorPos(3, oy + ly - 1)
                term.clearLine()
                for lx = 1, width do 
                    term.blit('\x8F ', (lx == x and ly == y) and '00' or '77', 'ff') 
                end
            end
            
            term.setCursorPos(3, oy + height)
            term.write('(' .. x .. ', ' .. y .. ')')
            term.setCursorPos(1, oy)
            
            -- 等待用户点击显示器
            repeat
                local _, name = os.pullEvent('monitor_touch')
                monitors[y][x] = name
            until not names[name]
            
            names[monitors[y][x]] = true
            sleep(0.25)
        end
    end
    
    settings.set('sanjuuni.multimonitor', monitors)
    settings.save()
    print('Calibration complete. Settings have been saved for future use.')
    
    return monitors
end

-- 播放图像/动画
function bimg.play(source, options)
    options = options or {}
    local termObj = options.terminal or term
    local loop = options.loop or false
    local isURL = options.isURL or false
    
    -- 停止当前播放
    bimg.stop()
    
    -- 加载图像数据
    local img
    if type(source) == "string" then
        if isURL then
            img = bimg.loadFromURL(source)
        else
            img = bimg.loadFromFile(source)
        end
    else
        img = loadImageData(source)
    end
    
    -- 设置运行标志
    running = true
    currentAnimation = {
        img = img,
        term = termObj,
        running = true,
        loop = loop
    }
    
    local function playFrames()
        repeat
            if img.multiMonitor then
                local width, height = img.multiMonitor.width, img.multiMonitor.height
                local monitors = settings.get('sanjuuni.multimonitor')
                
                -- 如果需要校准显示器
                if not monitors or #monitors < height or #monitors[1] < width then
                    monitors = calibrateMonitors(width, height)
                end
                
                -- 播放多显示器动画
                for i = 1, #img, width * height do
                    if not currentAnimation or not currentAnimation.running then break end
                    
                    -- 在所有显示器上绘制当前帧
                    for y = 1, height do
                        for x = 1, width do
                            local frameIndex = i + (y-1) * width + x-1
                            if frameIndex <= #img then
                                local monitor = peripheral.wrap(monitors[y][x])
                                if monitor then
                                    drawFrame(img[frameIndex], monitor)
                                end
                            end
                        end
                    end
                    
                    -- 等待帧间隔
                    if img.animation then 
                        sleep(img[i].duration or img.secondsPerFrame or 0.05)
                    else 
                        break 
                    end
                end
            else
                -- 单显示器播放
                termObj.clear()
                
                -- 播放每一帧
                for _, frame in ipairs(img) do
                    if not currentAnimation or not currentAnimation.running then break end
                    
                    drawFrame(frame, termObj)
                    
                    -- 等待帧间隔
                    if img.animation then 
                        sleep(frame.duration or img.secondsPerFrame or 0.05)
                    else 
                        break 
                    end
                end
            end
            
            -- 如果不是循环播放，则退出
            if not currentAnimation or not currentAnimation.loop then
                break
            end
            
        until not currentAnimation or not currentAnimation.running
    end
    
    -- 播放结束后的清理
    local function cleanup()
        if currentAnimation and currentAnimation.running then
            local termObj = currentAnimation.term
            
            -- 重置终端状态
            termObj.setBackgroundColor(colors.black)
            termObj.setTextColor(colors.white)
            termObj.clear()
            termObj.setCursorPos(1, 1)
            
            -- 重置调色板
            for i = 0, 15 do 
                termObj.setPaletteColor(2^i, term.nativePaletteColor(2^i)) 
            end
        end
        
        running = false
        currentAnimation = nil
    end
    
    -- 在新线程中播放
    parallel.waitForAny(
        function()
            local success, err = pcall(playFrames)
            if not success then
                printError("Error playing animation: " .. err)
            end
            cleanup()
        end,
        function()
            while currentAnimation and currentAnimation.running do
                os.pullEvent("bimg_stop")
                currentAnimation.running = false
            end
        end
    )
end

-- 停止播放
function bimg.stop()
    if currentAnimation then
        currentAnimation.running = false
        os.queueEvent("bimg_stop")
    end
    running = false
end

-- 检查是否正在播放
function bimg.isPlaying()
    return running
end

-- 获取当前播放状态
function bimg.getStatus()
    if not currentAnimation then
        return {
            playing = false,
            looping = false,
            frameCount = 0,
            currentFrame = 0
        }
    end
    
    return {
        playing = currentAnimation.running,
        looping = currentAnimation.loop,
        frameCount = #currentAnimation.img,
        currentFrame = currentAnimation.currentFrame or 0
    }
end

return bimg