local ADDON_NAME, RPAL = ...
RPAL = RPAL or _G.ODYN or _G.RPAL
if type(RPAL)~="table" then return end

-- Interaction customizations ------------------------------------------------
-- Keep the authored pixel assets close to their native size. Large toast and
-- tooltip surfaces are drawn with crisp 1px/2px UI lines; the supplied art is
-- used only as small accents, so it never gets blown up into a blurry frame.

local TEX="Interface\\AddOns\\ODYN\\Textures\\Interaction\\"
local WHITE="Interface\\Buttons\\WHITE8X8"
local GOLD={0.92,0.72,0.34,1}

RPAL.TOAST_FRAMES={
    order={"Classic","Gilded Dispatch","Crimson Dispatch","Field Journal","Heirloom Chronicle"},
    costs={Classic=0},
    descriptions={
        Classic="The original restrained ODYN toast border.",
        ["Gilded Dispatch"]="A clean gold dispatch rule with small ribbon tabs.",
        ["Crimson Dispatch"]="A sharp court-red dispatch rule for urgent rewards.",
        ["Field Journal"]="A compact double-rule field-note treatment.",
        ["Heirloom Chronicle"]="A ceremonial double border with a restrained archive crest.",
    },
    styles={
        Classic={mode="classic"},
        ["Gilded Dispatch"]={mode="rules",left=TEX.."ribbon_gold_right.tga",right=TEX.."ribbon_gold_left.tga",color={1.00,0.86,0.55}},
        ["Crimson Dispatch"]={mode="rules",left=TEX.."ribbon_red_right.tga",right=TEX.."ribbon_red_left.tga",color={1.00,0.34,0.40}},
        ["Field Journal"]={mode="double",pointer=TEX.."pointer_pagefold.tga",pointerPoint="TOPRIGHT",useAccent=true},
        ["Heirloom Chronicle"]={mode="double",crown=TEX.."large02_header.tga",color={1.00,0.82,0.42},heirloom=true},
    },
}

RPAL.TOOLTIP_TREATMENTS={
    order={"Classic","Pagefold Note","Maplefall Pointer","Ribbon Annotation","Heirloom Marginalia"},
    costs={Classic=0},
    descriptions={
        Classic="The original ODYN cursor tooltip.",
        ["Pagefold Note"]="A clean note border with a small folded-page marker.",
        ["Maplefall Pointer"]="A compact Maplefall pointer with a crisp accent rule.",
        ["Ribbon Annotation"]="A restrained annotation border with a ribbon marker.",
        ["Heirloom Marginalia"]="A double archival rule with a small ceremonial header.",
    },
    styles={
        Classic={mode="classic"},
        ["Pagefold Note"]={mode="double",pointer=TEX.."pointer_pagefold.tga",pointerPoint="TOPRIGHT"},
        ["Maplefall Pointer"]={mode="rules",pointer=TEX.."pointer_maplefall.tga",pointerPoint="BOTTOMLEFT",useAccent=true},
        ["Ribbon Annotation"]={mode="rules",pointer=TEX.."pointer_ribbon.tga",pointerPoint="BOTTOM",color={1.00,0.68,0.30}},
        ["Heirloom Marginalia"]={mode="double",pointer=TEX.."pointer_pagefold.tga",pointerPoint="TOPRIGHT",crown=TEX.."large01_header.tga",color={1.00,0.84,0.50},heirloom=true},
    },
}

RPAL.FOCUS_MARKS={
    order={"Classic","Maplefall Corners","Folio Brackets","Moonlit Trace","Heirloom Compass"},
    costs={Classic=0},
    descriptions={
        Classic="The original border response with no added focus art.",
        ["Maplefall Corners"]="Four restrained Maplefall corners appear around hovered controls.",
        ["Folio Brackets"]="Four compact folio brackets lock onto the active control.",
        ["Moonlit Trace"]="A thin cool-blue outline around the focused control.",
        ["Heirloom Compass"]="A restrained double-gold outline reserved for the season finale.",
    },
    styles={
        Classic={mode="classic"},
        ["Maplefall Corners"]={mode="corners",texture=TEX.."highlighter_corner.tga",size=18,color={0.42,0.80,1.00}},
        ["Folio Brackets"]={mode="corners",texture=TEX.."highlighter_brackets.tga",size=18,useAccent=true},
        ["Moonlit Trace"]={mode="rules",color={0.46,0.72,1.00}},
        ["Heirloom Compass"]={mode="double",color={1.00,0.84,0.44},heirloom=true},
    },
}

local focusTargets=setmetatable({},{__mode="k"})

local function Selection(key,fallback)
    local appearance=RPAL.GetCosmeticSelection and RPAL.GetCosmeticSelection() or {}
    return appearance[key] or fallback
end

local function Tint(style,accent)
    if style and style.useAccent and type(accent)=="table" then return accent end
    return style and style.color or accent or GOLD
end

local function EnsureSurfaceHolder(parent,key,levelOffset,pad)
    local holder=parent[key]
    if type(holder)~="table" and type(holder)~="userdata" then
        holder=CreateFrame("Frame",nil,parent);parent[key]=holder
    elseif holder:GetParent()~=parent then holder:SetParent(parent) end
    pad=tonumber(pad) or 4
    holder:ClearAllPoints();holder:SetPoint("TOPLEFT",parent,"TOPLEFT",-pad,pad);holder:SetPoint("BOTTOMRIGHT",parent,"BOTTOMRIGHT",pad,-pad)
    holder:EnableMouse(false);holder:SetClipsChildren(false)
    if parent.GetFrameLevel and holder.SetFrameLevel then holder:SetFrameLevel((parent:GetFrameLevel() or 0)+(levelOffset or 18)) end
    return holder
end

local function EnsureTexture(holder,key,layer,sublevel)
    local texture=holder[key]
    if not texture then texture=holder:CreateTexture(nil,layer or "OVERLAY",nil,math.max(-8,math.min(7,tonumber(sublevel) or 0)));holder[key]=texture end
    texture:ClearAllPoints();texture:SetTexCoord(0,1,0,1);if texture.SetRotation then texture:SetRotation(0) end
    return texture
end

local ALL_REGIONS={"top","bottom","leftLine","rightLine","innerTop","innerBottom","innerLeft","innerRight","left","right","crown","pointer","full"}
local function HideSurface(holder)
    if not holder then return end
    holder:Hide()
    for _,key in ipairs(ALL_REGIONS) do local region=holder[key];if region then region:Hide() end end
    if holder.corners then for _,region in ipairs(holder.corners) do region:Hide() end end
end

local function Line(holder,key,c,alpha,thickness)
    local t=EnsureTexture(holder,key,"OVERLAY",2);t:SetTexture(WHITE);t:SetVertexColor(c[1] or 1,c[2] or 1,c[3] or 1,alpha or .9);return t,math.max(1,tonumber(thickness) or 1)
end

local function DrawRules(holder,c,doubleRule,alpha)
    local top,w=Line(holder,"top",c,alpha,1);top:SetPoint("TOPLEFT",2,-2);top:SetPoint("TOPRIGHT",-2,-2);top:SetHeight(w);top:Show()
    local bottom=Line(holder,"bottom",c,alpha,1);bottom:SetPoint("BOTTOMLEFT",2,2);bottom:SetPoint("BOTTOMRIGHT",-2,2);bottom:SetHeight(w);bottom:Show()
    local left=Line(holder,"leftLine",c,alpha,1);left:SetPoint("TOPLEFT",2,-2);left:SetPoint("BOTTOMLEFT",2,2);left:SetWidth(w);left:Show()
    local right=Line(holder,"rightLine",c,alpha,1);right:SetPoint("TOPRIGHT",-2,-2);right:SetPoint("BOTTOMRIGHT",-2,2);right:SetWidth(w);right:Show()
    for _,key in ipairs({"innerTop","innerBottom","innerLeft","innerRight"}) do if holder[key] then holder[key]:Hide() end end
    if doubleRule then
        local it,iw=Line(holder,"innerTop",c,(alpha or .9)*.48,1);it:SetPoint("TOPLEFT",6,-6);it:SetPoint("TOPRIGHT",-6,-6);it:SetHeight(iw);it:Show()
        local ib=Line(holder,"innerBottom",c,(alpha or .9)*.48,1);ib:SetPoint("BOTTOMLEFT",6,6);ib:SetPoint("BOTTOMRIGHT",-6,6);ib:SetHeight(iw);ib:Show()
        local il=Line(holder,"innerLeft",c,(alpha or .9)*.48,1);il:SetPoint("TOPLEFT",6,-6);il:SetPoint("BOTTOMLEFT",6,6);il:SetWidth(iw);il:Show()
        local ir=Line(holder,"innerRight",c,(alpha or .9)*.48,1);ir:SetPoint("TOPRIGHT",-6,-6);ir:SetPoint("BOTTOMRIGHT",-6,6);ir:SetWidth(iw);ir:Show()
    end
end

local function PlacePointer(holder,style,c,size)
    local pointer=EnsureTexture(holder,"pointer","OVERLAY",5)
    if not style.pointer then pointer:Hide();return end
    pointer:SetTexture(style.pointer);pointer:SetSize(size or 24,size or 24);pointer:SetVertexColor(c[1] or 1,c[2] or 1,c[3] or 1,.96)
    local point=style.pointerPoint or "BOTTOMLEFT"
    if point=="TOPRIGHT" then pointer:SetPoint("TOPRIGHT",-10,12)
    elseif point=="BOTTOM" then pointer:SetPoint("BOTTOM",0,-12)
    else pointer:SetPoint("BOTTOMLEFT",10,-12) end
    pointer:Show()
end

local function PlaceCrown(holder,style,c,width)
    local crown=EnsureTexture(holder,"crown","OVERLAY",4)
    if not style.crown then crown:Hide();return end
    local w=math.max(110,math.min(width or 190,220));local h=math.floor(w*(150/430))
    crown:SetTexture(style.crown);crown:SetSize(w,h);crown:SetPoint("TOP",0,math.floor(h*.30));crown:SetVertexColor(c[1] or 1,c[2] or 1,c[3] or 1,.72);crown:Show()
end

function RPAL.ApplyToastFrameCustomization(frame,accent,overrideName)
    if not frame then return nil end
    local name=overrideName or Selection("toastFrame","Classic")
    local style=RPAL.TOAST_FRAMES.styles[name] or RPAL.TOAST_FRAMES.styles.Classic
    local holder=frame._odynToastFrameTreatment
    if style.mode=="classic" then HideSurface(holder);return nil end
    holder=EnsureSurfaceHolder(frame,"_odynToastFrameTreatment",24,4);HideSurface(holder)
    local c=Tint(style,accent);DrawRules(holder,c,style.mode=="double",.88)

    local left=EnsureTexture(holder,"left","OVERLAY",3);local right=EnsureTexture(holder,"right","OVERLAY",3)
    if style.left and style.right then
        local h=math.max(36,math.min(54,(frame.GetHeight and frame:GetHeight() or 72)*.62));local w=math.floor(h*.60)
        left:SetTexture(style.left);left:SetSize(w,h);left:SetPoint("LEFT",-math.floor(w*.42),0);left:SetVertexColor(1,1,1,.88);left:Show()
        right:SetTexture(style.right);right:SetSize(w,h);right:SetPoint("RIGHT",math.floor(w*.42),0);right:SetVertexColor(1,1,1,.88);right:Show()
    else left:Hide();right:Hide() end
    PlacePointer(holder,style,c,22)
    PlaceCrown(holder,style,c,math.min(205,(frame.GetWidth and frame:GetWidth() or 430)*.42))
    holder:Show();return holder
end

function RPAL.ApplyTooltipTreatment(frame,accent,overrideName)
    if not frame then return nil end
    local name=overrideName or Selection("tooltipTreatment","Classic")
    local style=RPAL.TOOLTIP_TREATMENTS.styles[name] or RPAL.TOOLTIP_TREATMENTS.styles.Classic
    local holder=frame._odynTooltipTreatment
    if style.mode=="classic" then HideSurface(holder);return nil end
    holder=EnsureSurfaceHolder(frame,"_odynTooltipTreatment",26,3);HideSurface(holder)
    local c=Tint(style,accent);DrawRules(holder,c,style.mode=="double",.84)
    PlacePointer(holder,style,c,22)
    PlaceCrown(holder,style,c,math.min(180,(frame.GetWidth and frame:GetWidth() or 320)*.48))
    holder:Show();return holder
end

local function EnsureFocusHolder(button)
    local holder=button._odynFocusMark
    if not holder then
        holder=CreateFrame("Frame",nil,button);button._odynFocusMark=holder;holder.corners={}
        for index=1,4 do holder.corners[index]=holder:CreateTexture(nil,"OVERLAY",nil,7) end
    end
    holder:ClearAllPoints();holder:SetPoint("TOPLEFT",button,"TOPLEFT",-4,4);holder:SetPoint("BOTTOMRIGHT",button,"BOTTOMRIGHT",4,-4);holder:EnableMouse(false)
    if button.GetFrameLevel then holder:SetFrameLevel((button:GetFrameLevel() or 0)+30) end
    return holder
end

function RPAL.RefreshFocusMark(button,forceShown,overrideName,accent)
    if not button then return nil end
    local holder=EnsureFocusHolder(button)
    local name=overrideName or Selection("focusMark","Classic")
    local style=RPAL.FOCUS_MARKS.styles[name] or RPAL.FOCUS_MARKS.styles.Classic
    if style.mode=="classic" or not forceShown then holder:Hide();return holder end
    HideSurface(holder);local c=Tint(style,accent or button._rpalInteractionAccent or GOLD)
    if style.mode=="corners" then
        local points={
            {"BOTTOMLEFT",0,1,0,1},{"BOTTOMRIGHT",1,0,0,1},
            {"TOPRIGHT",1,0,1,0},{"TOPLEFT",0,1,1,0},
        }
        local size=tonumber(style.size) or 18
        for index,definition in ipairs(points) do
            local corner=holder.corners[index];corner:SetTexture(style.texture);corner:SetSize(size,size);corner:ClearAllPoints();corner:SetPoint(definition[1],0,0);corner:SetTexCoord(definition[2],definition[3],definition[4],definition[5]);corner:SetVertexColor(c[1] or 1,c[2] or 1,c[3] or 1,.96);corner:Show()
        end
    else
        DrawRules(holder,c,style.mode=="double",style.heirloom and .98 or .90)
    end
    holder:Show();return holder
end

function RPAL.AttachFocusMark(button,accent)
    if not button or button._odynFocusMarkAttached then return button end
    button._odynFocusMarkAttached=true;button._rpalInteractionAccent=accent or button._rpalInteractionAccent;focusTargets[button]=true
    button:HookScript("OnEnter",function(self)RPAL.RefreshFocusMark(self,true)end)
    button:HookScript("OnLeave",function(self)RPAL.RefreshFocusMark(self,false)end)
    button:HookScript("OnMouseDown",function(self)RPAL.RefreshFocusMark(self,true)end)
    button:HookScript("OnDisable",function(self)RPAL.RefreshFocusMark(self,false)end)
    return button
end

function RPAL.RefreshFocusMarks()
    for button in pairs(focusTargets) do if button and button.IsMouseOver then RPAL.RefreshFocusMark(button,button:IsMouseOver()) end end
end

function RPAL.RenderInteractionCustomizationPreview(parent,kind,name,accent)
    if not parent then return nil end
    accent=accent or GOLD
    local sample=CreateFrame(kind=="focus" and "Button" or "Frame",nil,parent,"BackdropTemplate")
    if parent.GetFrameLevel then sample:SetFrameLevel((parent:GetFrameLevel() or 0)+30) end
    sample:SetBackdrop({bgFile=WHITE,edgeFile=WHITE,edgeSize=1});sample:SetBackdropColor(.025,.020,.040,.96);sample:SetBackdropBorderColor(accent[1],accent[2],accent[3],.26)
    local available=(parent.GetWidth and parent:GetWidth()) or 220;if available<=0 then available=220 end
    if kind=="toast" then sample:SetSize(math.min(214,available-12),62);sample:SetPoint("CENTER");RPAL.ApplyToastFrameCustomization(sample,accent,name)
    elseif kind=="tooltip" then sample:SetSize(math.min(204,available-12),78);sample:SetPoint("CENTER");RPAL.ApplyTooltipTreatment(sample,accent,name)
    else sample:SetSize(math.min(174,available-12),46);sample:SetPoint("CENTER");RPAL.RefreshFocusMark(sample,true,name,accent) end
    local text=sample:CreateFontString(nil,"OVERLAY");text:SetFont("Fonts\\FRIZQT__.TTF",9,"OUTLINE");text:SetTextColor(.94,.91,.84,1);text:SetPoint("CENTER");text:SetText(kind=="toast" and "REWARD UNLOCKED" or (kind=="tooltip" and "CURSOR NOTE" or "FOCUSED CONTROL"))
    return sample
end
