--[[
    LogicBeacon - 多状态像素编码器
    在屏幕角落显示横向像素条，每个像素对应一个游戏状态，
    供外部 Python 等脚本截取小区域即可获取完整状态机。
]]

-- 配置：10个状态位（1个白色锚点 + 9个数据位）
local PIXEL_SIZE = 10
local STATUS_COUNT = 10
local ADDON_NAME = "LogicBeacon"

-- 默认配置（可被 SavedVariables 覆盖）
local defaults = {
    pixelSize = PIXEL_SIZE,
    statusCount = STATUS_COUNT,
    point = "TOPLEFT",
    x = 10,  -- 整体向右偏移 10 像素
    y = 0,
    scale = 1,
    locked = false,
}

-- 确保每角色存储存在
LogicBeaconDB = LogicBeaconDB or {}
for k, v in pairs(defaults) do
    if LogicBeaconDB[k] == nil then
        LogicBeaconDB[k] = v
    end
end
-- 升级：至少 10 个状态位（含跟随信号）
LogicBeaconDB.statusCount = math.max(LogicBeaconDB.statusCount or 0, 10)

local db = LogicBeaconDB

-- 主框架
local f = CreateFrame("Frame", "LogicBeaconFrame", UIParent)
local totalW = db.pixelSize * db.statusCount
local totalH = db.pixelSize

f:SetSize(totalW, totalH)
f:SetScale(db.scale)
f:SetPoint(db.point, UIParent, db.point, db.x, db.y)
f:SetFrameStrata("TOOLTIP")
f:SetClampedToScreen(true)

-- 背景底色（防止半透明干扰）
local bg = f:CreateTexture(nil, "BACKGROUND")
bg:SetAllPoints()
bg:SetColorTexture(0, 0, 0, 1)

-- 像素纹理（[1]=锚点 [2~10]=数据位）
local pixels = {}
for i = 1, db.statusCount do
    local tex = f:CreateTexture(nil, "OVERLAY")
    tex:SetSize(db.pixelSize, db.pixelSize)
    tex:SetPoint("LEFT", f, "LEFT", (i - 1) * db.pixelSize, 0)
    pixels[i] = tex
end

-- 后勤位：背包空格、装备耐久、死亡/灵魂状态
local function GetLogisticsInfo()
    -- 1. 检查背包空格 (0 - 100+)
    local freeSlots = 0
    for i = 0, 4 do
        local numFree = GetContainerNumFreeSlots(i)
        freeSlots = freeSlots + numFree
    end

    -- 2. 检查装备最低耐久度 (0.0 - 1.0)
    local minDurability = 1
    for i = 1, 18 do
        local current, maximum = GetInventoryItemDurability(i)
        if current and maximum and maximum > 0 then
            minDurability = math.min(minDurability, current / maximum)
        end
    end

    -- 3. 死亡状态 (0:存活, 0.5:死尸, 1.0:灵魂)
    local dState = 0
    if UnitIsGhost("player") then
        dState = 1.0
    elseif UnitIsDead("player") then
        dState = 0.5
    end

    return freeSlots, minDurability, dState
end

-- 地图坐标（现代 C_Map API，返回 0~1 比例）
local function GetPlayerCoords()
    local mapID = C_Map.GetBestMapForUnit("player")
    if mapID then
        local mapPos = C_Map.GetPlayerMapPosition(mapID, "player")
        if mapPos then
            return mapPos:GetXY()
        end
    end
    return 0, 0
end

-- 专门用于计算飞行信号的函数（R 通道：0 未上马 / 0.5 可起飞需按空格 / 1.0 已在飞）
local function GetFlightSignal()
    local isMounted = IsMounted()
    local isFlying = IsFlying()
    local canFly = IsFlyableArea()

    if not isMounted then
        return 0
    end

    if isMounted and canFly and not isFlying then
        if not UnitAffectingCombat("player") and IsOutdoors() then
            return 0.5
        end
    end

    if isMounted and isFlying then
        return 1.0
    end

    return 0
end

-- 专门用于计算跟随信号的函数（R 通道：0 未组队 / 0.5 需补跟随 / 1.0 跟随中）
local function GetFollowSignal()
    if not IsInGroup() then
        return 0
    end

    local leader = "party1"

    if IsFollowing() then
        return 1.0
    else
        if UnitExists(leader) and UnitIsVisible(leader) then
            return 0.5
        end
    end
    return 0
end

f:SetScript("OnUpdate", function()
    -- [1] 锚点：永远纯白 (255, 255, 255)
    pixels[1]:SetColorTexture(1, 1, 1)

    -- [2] 血量：红色通道
    local hp = UnitHealth("player") / math.max(1, UnitHealthMax("player"))
    local targetHp = UnitHealth("target") / math.max(1, UnitHealthMax("target"))
    pixels[2]:SetColorTexture(hp, targetHp, 0)

    -- [3] 法力/能量：蓝色通道
    local mp = UnitPower("player") / math.max(1, UnitPowerMax("player"))
    pixels[3]:SetColorTexture(0, 0, mp)

    -- [4] 战斗状态：绿色通道 (255=战斗中)
    if UnitAffectingCombat("player") then
        pixels[4]:SetColorTexture(0, 1, 0)
    else
        pixels[4]:SetColorTexture(0, 0, 0)
    end

    -- [5] 目标状态：红色通道 (255=有敌对目标)
    -- 逻辑：可以攻击 AND 目标不是玩家 AND 不是灰名怪 AND 不是玩家宠物
    if UnitCanAttack("player", "target") and not UnitIsPlayer("target") and not UnitIsTapDenied("target") and not UnitPlayerControlled("target") then
        -- 只有满足这三个条件，才输出“有效目标”信号（红色）
        pixels[5]:SetColorTexture(1, 0, 0)
    else
        -- 只要其中一个条件不满足（比如怪被抢了，或者是玩家），就输出黑色
        pixels[5]:SetColorTexture(0, 0, 0)
    end

    -- [6] 综合后勤与死亡位
    local free, repair, dead = GetLogisticsInfo()
    -- R: 空格数 (0-1，Python *255 还原)
    -- G: 耐久度 (0-1)
    -- B: 死亡状态 (0=存活, 0.5=死尸, 1.0=灵魂)
    pixels[6]:SetColorTexture(free / 255, repair, dead)

    -- [7][8] 地图坐标与朝向（C_Map 现代 API，0~1 比例）
    local mapX, mapY = GetPlayerCoords()
    local facing = GetPlayerFacing() or 0
    -- [7] X：R=整数部分(×100)，G=小数部分，B=朝向/2π
    pixels[7]:SetColorTexture(
        math.floor(mapX * 100) / 255,
        math.floor((mapX * 10000) % 100) / 255,
        facing / 6.28318
    )
    -- [8] Y：R=整数部分(×100)，G=小数部分，B=预留
    pixels[8]:SetColorTexture(
        math.floor(mapY * 100) / 255,
        math.floor((mapY * 10000) % 100) / 255,
        0
    )

    -- [9] R=飞行信号 GetFlightSignal()，G=上马(1/0)，B=可飞区域 IsFlyableArea()
    local fSignal = GetFlightSignal()
    local mountedSig = IsMounted() and 1 or 0
    local canFlySig = IsFlyableArea() and 1 or 0
    pixels[9]:SetColorTexture(fSignal, mountedSig, canFlySig, 1)

    -- [10] R=跟随信号（0 / 0.5 需补跟随 / 1.0 跟随中）
    local followSig = GetFollowSignal()
    pixels[10]:SetColorTexture(followSig, 0, 0, 1)
end)

-- 可拖动
f:SetMovable(not db.locked)
f:EnableMouse(not db.locked)
f:RegisterForDrag("LeftButton")

f:SetScript("OnDragStart", function()
    if not db.locked then
        f:StartMoving()
    end
end)

f:SetScript("OnDragStop", function()
    f:StopMovingOrSizing()
    local _, _, _, x, y = f:GetPoint(1)
    db.x = x
    db.y = y
end)

-- 右键菜单：锁定/解锁、重置位置
local menu = CreateFrame("Frame", "LogicBeaconMenu", f, "UIDropDownMenuTemplate")
f:SetScript("OnMouseDown", function(_, button)
    if button == "RightButton" then
        local menuList = {
            {
                text = db.locked and "解锁位置" or "锁定位置",
                func = function()
                    db.locked = not db.locked
                    f:SetMovable(not db.locked)
                    f:EnableMouse(not db.locked)
                end,
            },
            {
                text = "重置到左上角",
                func = function()
                    db.point = "TOPLEFT"
                    db.x = 10
                    db.y = 0
                    f:ClearAllPoints()
                    f:SetPoint(db.point, UIParent, db.point, db.x, db.y)
                end,
            },
        }
        EasyMenu(menuList, menu, "cursor", 0, 0, "MENU")
    end
end)

-- 登录完成后确保显示
local event = CreateFrame("Frame")
event:RegisterEvent("PLAYER_LOGIN")
event:SetScript("OnEvent", function()
    f:Show()
end)

-- Slash 命令
SlashCmdList["LOGICBEACON"] = function(msg)
    msg = msg:lower():gsub("^%s*(.-)%s*$", "%1")
    if msg == "lock" or msg == "锁定" then
        db.locked = true
        f:SetMovable(false)
        f:EnableMouse(false)
        print("|cff00ff00[LogicBeacon]|r 已锁定")
    elseif msg == "unlock" or msg == "解锁" then
        db.locked = false
        f:SetMovable(true)
        f:EnableMouse(true)
        print("|cff00ff00[LogicBeacon]|r 已解锁")
    elseif msg == "reset" or msg == "重置" then
        db.point, db.x, db.y = "TOPLEFT", 10, 0
        f:ClearAllPoints()
        f:SetPoint(db.point, UIParent, db.point, db.x, db.y)
        print("|cff00ff00[LogicBeacon]|r 已重置到左上角")
    else
        print("|cff00ff00[LogicBeacon]|r 用法: /lb lock|unlock|reset （锁定|解锁|重置位置）")
    end
end
SLASH_LOGICBEACON1 = "/lb"
SLASH_LOGICBEACON2 = "/logicbeacon"

print("|cff00ff00[LogicBeacon]|r 已加载。右键像素条可锁定/重置，/lb 查看命令。")
