-------------------------------------------------------------------------------
--  EllesmereUI_koKR_Plus / Core.lua   (가장 먼저 로드)
--  공용 인프라 한 곳:
--    · 네임스페이스 EUIKorPlus, SavedVariables(EllesmereUIKorAdditionsDB), 공용 헬퍼
--    · 메인 "추가 기능" 팝업 프레임 + 섹션 등록 API + 자동 레이아웃
--    · EUI 메인프레임 우상단 "추가 기능" 버튼 + 진입점 + 진단
--
--  ★ 모듈성: 각 기능은 자기 파일에서 NS.RegisterSection / NS.RegisterInstall /
--    NS.RegisterOnShow / NS.RegisterDiag 로 *자기 자신을 등록*한다. 기능 파일을
--    toc 에서 빼면 등록이 안 돼 섹션·후크가 통째로 사라진다(에러 0, 사용량 0).
--    Core 는 특정 기능 함수를 직접 부르지 않는다(전부 등록 목록 순회 + nil 가드).
--
--  ※ Castbar.lua / MinimapPin.lua 는 자체 DB·팝업·헬퍼를 가진 독립 도메인.
--    여기 헬퍼/DB 와 섞지 않는다.
-------------------------------------------------------------------------------
---@diagnostic disable: undefined-global

local NS = _G.EUIKorPlus or {}
_G.EUIKorPlus = NS
_G.__cimkrAdditionsActive = true   -- Core(번역본) 가 보는 "추가기능 존재" 플래그

-- ============================================================
--  SavedVariables (이름 유지 — 번역본 Core.lua 가 직접 읽음)
-- ============================================================
local DEFAULTS = {
    popupScale       = 1.0,
    settingsTipScale = 1.0,
    eqsetIcon        = true,
    hotkeyShorten    = true,
    cdmHotkeyShorten = true,
    charSheetScale   = 1.0,
    inspectScale     = 1.0,
    ddItemFontMatch  = false,
    ddItemFontSize   = 13,
    npExtraY         = 0,
    widgetScale      = 1.0,
    popupSkinScale   = 1.0,
    -- (castbarBgAlpha → EllesmereUI_koKR_Plus/Castbar.lua 도메인으로 이동)
    -- (minimapRightClick / microMenuScale → MinimapPin.lua 도메인으로 이동)
}
NS.DEFAULTS = DEFAULTS

-- 값 범위 (기능 파일에서 NS.RANGE 로 참조)
NS.RANGE = {
    POPUP  = { 0.5, 3.0, 0.1 },
    TIP    = { 1.0, 2.0, 0.1 },
    NP_Y   = { -50, 200, 1 },
    WS     = { 0.5, 2.0, 0.05 },
    CS     = { 0.5, 2.0, 0.05 },
    DDF    = { 9, 20, 1 },
}

local POPUP_SCALE_MIN, POPUP_SCALE_MAX, POPUP_SCALE_STEP = 0.5, 3.0, 0.1

-- 누락 키만 매번 머지(저장값 보존). PLAYER_LOGIN 후 잠금.
local _dbReady = false
local function GetDB()
    EllesmereUIKorAdditionsDB = EllesmereUIKorAdditionsDB or {}
    local db = EllesmereUIKorAdditionsDB
    if not _dbReady then
        for k, v in pairs(DEFAULTS) do
            if db[k] == nil then db[k] = v end
        end
    end
    return db
end
NS.GetDB = GetDB

-- ============================================================
--  공용 UI 헬퍼 (구 Additions 와 동일 구현)
-- ============================================================
local function GetFont()
    -- 추가기능(한글)의 모든 글자는 클라 한글 폰트(2002.TTF)를 사용.
    --   EllesmereUI.EXPRESSWAY 는 영문 전용(한글 글리프 없음 → □) 이라 쓰지 않는다.
    return "Fonts\\2002.TTF"
end

local function SolidTex(parent, layer, r, g, b, a, sub)
    local t = parent:CreateTexture(nil, layer or "BACKGROUND", nil, sub)
    t:SetColorTexture(r, g, b, a)
    return t
end

local function MakeFont(parent, size, flags, r, g, b, a)
    local fs = parent:CreateFontString(nil, "OVERLAY")
    fs:SetFont(GetFont(), size or 12, flags or "")
    fs:SetTextColor(r or 1, g or 1, b or 1, a or 1)
    return fs
end

local function MakeDescFS(parent, size, r, g, b, a)
    local fs = MakeFont(parent, size, nil, r, g, b, a)
    fs:SetShadowOffset(1, -1)
    fs:SetShadowColor(0, 0, 0, 1)
    fs:SetSpacing(4)
    return fs
end

local function MakeBorder(frame, r, g, b, a)
    local t1 = frame:CreateTexture(nil, "BORDER")
    local t2 = frame:CreateTexture(nil, "BORDER")
    local t3 = frame:CreateTexture(nil, "BORDER")
    local t4 = frame:CreateTexture(nil, "BORDER")
    for _, t in ipairs({ t1, t2, t3, t4 }) do t:SetColorTexture(r, g, b, a) end
    t1:SetPoint("TOPLEFT");     t1:SetPoint("TOPRIGHT");    t1:SetHeight(1)
    t2:SetPoint("BOTTOMLEFT");  t2:SetPoint("BOTTOMRIGHT"); t2:SetHeight(1)
    t3:SetPoint("TOPLEFT");     t3:SetPoint("BOTTOMLEFT");  t3:SetWidth(1)
    t4:SetPoint("TOPRIGHT");    t4:SetPoint("BOTTOMRIGHT"); t4:SetWidth(1)
    return { t1, t2, t3, t4 }
end

local function SetBorderColor(borders, r, g, b, a)
    for _, t in ipairs(borders) do t:SetColorTexture(r, g, b, a) end
end

local function MakeStepBtn(parent, side, char, fn)
    local b = CreateFrame("Button", nil, parent)
    b:SetSize(22, 22)
    b:SetPoint(side, parent, side, 0, 0)
    local fs = MakeFont(b, 14, "OUTLINE", 0.73, 0.73, 0.73)
    fs:SetPoint("CENTER")
    fs:SetText(char)
    b:SetScript("OnEnter", function() fs:SetTextColor(1.0, 0.6, 0.1) end)
    b:SetScript("OnLeave", function() fs:SetTextColor(0.73, 0.73, 0.73) end)
    b:SetScript("OnClick", fn)
    return b
end

-- 색상 상수
local POPUP_MAIN_BG   = { 0.12, 0.13, 0.15, 1 }
local POPUP_TITLE_BG  = { 0.17, 0.18, 0.20, 1 }
local POPUP_BTN_BG    = { 0.01, 0.02, 0.03, 1 }
local POPUP_STEP_BG   = { 0.01, 0.02, 0.03, 1 }
local POPUP_BTN_HOVER = { 0.20, 0.20, 0.22, 0.8 }

-- 온오프 스위치 (anchor 의 부모에 붙음 — 호출부 호환)
local function MakeSwitch(anchor, yoff, label, key, onChange)
    local EUI = _G.EllesmereUI
    local gC  = (EUI and EUI.ELLESMERE_GREEN) or { r = 0.05, g = 0.82, b = 0.61 }
    local TW, TH, PAD = 40, 20, 2
    local KN  = TH - PAD * 2
    local oTR = (EUI and EUI.TG_OFF_R) or 0.267
    local oTG = (EUI and EUI.TG_OFF_G) or 0.267
    local oTB = (EUI and EUI.TG_OFF_B) or 0.267
    local oTA = (EUI and EUI.TG_OFF_A) or 0.65
    local oKA = (EUI and EUI.TG_KNOB_OFF_A) or 0.5
    local nTA = (EUI and EUI.TG_ON_A) or 0.75
    local nKA = (EUI and EUI.TG_KNOB_ON_A) or 1

    local parent = anchor:GetParent() or UIParent
    local row = CreateFrame("Button", nil, parent)
    row:SetSize(220, 22)
    row:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, yoff)
    local lb = MakeFont(row, 11, nil, 0.62, 0.62, 0.68)
    lb:SetPoint("LEFT", row, "LEFT", 0, 0)
    lb:SetText(label)

    local sw = CreateFrame("Frame", nil, row)
    sw:SetSize(TW, TH)
    sw:SetPoint("LEFT", row, "LEFT", 150, 0)
    local tBg = SolidTex(sw, "BACKGROUND", oTR, oTG, oTB, oTA)
    tBg:SetAllPoints()
    local knob = sw:CreateTexture(nil, "ARTWORK")
    knob:SetSize(KN, KN)

    local function _upd()
        knob:ClearAllPoints()
        if GetDB()[key] ~= false then
            tBg:SetColorTexture(gC.r, gC.g, gC.b, nTA)
            knob:SetPoint("RIGHT", sw, "RIGHT", -PAD, 0)
            knob:SetColorTexture(1, 1, 1, nKA)
        else
            tBg:SetColorTexture(oTR, oTG, oTB, oTA)
            knob:SetPoint("LEFT", sw, "LEFT", PAD, 0)
            knob:SetColorTexture(1, 1, 1, oKA)
        end
    end
    row:SetScript("OnEnter", function() lb:SetTextColor(1, 1, 1) end)
    row:SetScript("OnLeave", function() lb:SetTextColor(0.62, 0.62, 0.68) end)
    row:SetScript("OnClick", function()
        local db = GetDB()
        db[key] = (db[key] == false) and true or false
        _upd()
        if onChange then onChange() end
    end)
    _upd()
    return row
end

-- 네임스페이스 노출
NS.GetFont, NS.SolidTex, NS.MakeFont, NS.MakeDescFS  = GetFont, SolidTex, MakeFont, MakeDescFS
NS.MakeBorder, NS.SetBorderColor, NS.MakeStepBtn     = MakeBorder, SetBorderColor, MakeStepBtn
NS.MakeSwitch = MakeSwitch
NS.COLORS = {
    MAIN = POPUP_MAIN_BG, TITLE = POPUP_TITLE_BG, BTN = POPUP_BTN_BG,
    STEP = POPUP_STEP_BG, HOVER = POPUP_BTN_HOVER,
}

-- ============================================================
--  등록 API — 기능 파일이 자기 자신을 여기 등록
-- ============================================================
NS._sections = NS._sections or {}   -- { {order, title, desc, build=fn(popup, descFS)} ... }
NS._onShow   = NS._onShow   or {}   -- 팝업 OnShow 시 호출
NS._installs = NS._installs or {}   -- 진입점(PLAYER_LOGIN)에서 호출
NS._diags    = NS._diags    or {}   -- 진단창에서 호출 fn(add, chk)

function NS.RegisterSection(t)  NS._sections[#NS._sections + 1] = t end
function NS.RegisterOnShow(fn)  NS._onShow[#NS._onShow + 1]     = fn end
function NS.RegisterInstall(fn) NS._installs[#NS._installs + 1] = fn end
function NS.RegisterDiag(fn)    NS._diags[#NS._diags + 1]       = fn end

-- 공용: [◀ 값 ▶] (+선택적 초기화) 스텝 행. 대부분의 수치 섹션이 이걸 쓴다.
-- o = { get, set, fmt, min, max, step, onChange, reset }  (reset: 함수면 OnClick, 값이면 그 값으로)
function NS.MakeStepperRow(popup, descFS, o)
    local row = CreateFrame("Frame", nil, popup)
    row:SetSize(170, 24)
    row:SetPoint("TOPLEFT", descFS, "BOTTOMLEFT", 0, -10)
    row:SetFrameLevel((popup:GetFrameLevel() or 0) + 10)
    SolidTex(row, "BACKGROUND", POPUP_STEP_BG[1], POPUP_STEP_BG[2], POPUP_STEP_BG[3], POPUP_STEP_BG[4]):SetAllPoints()
    local val = MakeFont(row, 12, nil, 0.62, 0.62, 0.68)
    val:SetPoint("CENTER")
    local function upd() val:SetText(o.fmt(o.get())) end
    local function clamp(v) return math.max(o.min, math.min(o.max, v)) end
    local bL = MakeStepBtn(row, "LEFT",  "◀", function()
        o.set(clamp((o.get() or o.min) - o.step)); if o.onChange then o.onChange() end; upd()
    end)
    local bR = MakeStepBtn(row, "RIGHT", "▶", function()
        o.set(clamp((o.get() or o.min) + o.step)); if o.onChange then o.onChange() end; upd()
    end)
    bL:SetFrameLevel(row:GetFrameLevel() + 1)
    bR:SetFrameLevel(row:GetFrameLevel() + 1)
    if o.reset ~= nil then
        local rb = CreateFrame("Button", nil, popup)
        rb:SetSize(60, 22)
        rb:SetPoint("LEFT", row, "RIGHT", 8, 0)
        local rbg = SolidTex(rb, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
        rbg:SetAllPoints()
        local rl = MakeFont(rb, 11, "OUTLINE", 0.62, 0.62, 0.68)
        rl:SetPoint("CENTER"); rl:SetText("초기화")
        rb:SetScript("OnEnter", function() rbg:SetColorTexture(POPUP_BTN_HOVER[1], POPUP_BTN_HOVER[2], POPUP_BTN_HOVER[3], POPUP_BTN_HOVER[4]) end)
        rb:SetScript("OnLeave", function() rbg:SetColorTexture(POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4]) end)
        rb:SetScript("OnClick", function()
            if type(o.reset) == "function" then o.reset() else o.set(o.reset) end
            if o.onChange then o.onChange() end; upd()
        end)
    end
    upd()
    return row, upd
end

-- ============================================================
--  메인 팝업 (lazy) — 등록된 섹션을 2열 자동 배치
-- ============================================================
local popup, popupDimmer

local function _div(p, hdr, colW)
    local ln = SolidTex(p, "ARTWORK", 0.45, 0.55, 0.70, 0.55)
    ln:ClearAllPoints()
    ln:SetPoint("BOTTOMLEFT", hdr, "TOPLEFT", -5, 6)
    ln:SetSize(colW - 7, 2)
    local hbg = SolidTex(p, "BACKGROUND", POPUP_TITLE_BG[1], POPUP_TITLE_BG[2], POPUP_TITLE_BG[3], POPUP_TITLE_BG[4], 1)
    hbg:ClearAllPoints()
    hbg:SetPoint("TOPLEFT",  ln, "BOTTOMLEFT",  0, 3)
    hbg:SetPoint("TOPRIGHT", ln, "BOTTOMRIGHT", 0, 3)
    hbg:SetHeight(26)
    return ln
end

local function CreatePopup()
    if popup then return popup, popupDimmer end

    -- 섹션 수집 (배치는 각 섹션이 지정한 col/row 고정 — 미지정 시 order 자동흐름 폴백)
    local secs = {}
    for _, s in ipairs(NS._sections) do secs[#secs + 1] = s end
    table.sort(secs, function(a, b) return (a.order or 100) < (b.order or 100) end)

    local COL_W   = 420
    local COL2_X  = 455
    local sectionY = -56
    local POPUP_W = 880
    -- 최대 행 계산 (col/row 명시분 + 폴백분 모두 고려)
    local maxRow, flow = 0, 0
    for _, s in ipairs(secs) do
        local r = s.row
        if r == nil then r = math.floor(flow / 2); flow = flow + 1 end
        if r > maxRow then maxRow = r end
    end
    local POPUP_H = math.max(220, 56 + (maxRow + 1) * 90 + 60)   -- 헤더 + 행*90 + 하단버튼

    local dimmer = CreateFrame("Frame", "CIMPlusDimmer", UIParent)
    popupDimmer = dimmer
    dimmer:SetFrameStrata("DIALOG"); dimmer:SetFrameLevel(500)
    dimmer:SetAllPoints(UIParent); dimmer:EnableMouse(false); dimmer:Hide()
    SolidTex(dimmer, "BACKGROUND", 0, 0, 0, 0.10):SetAllPoints()
    dimmer:EnableKeyboard(true)
    dimmer:SetPropagateKeyboardInput(true)
    dimmer:SetScript("OnKeyDown", function(self, key)
        if key == "ESCAPE" then self:SetPropagateKeyboardInput(false); self:Hide()
        else self:SetPropagateKeyboardInput(true) end
    end)

    popup = CreateFrame("Frame", "CIMPlusPopup", dimmer)
    popup:SetSize(POPUP_W, POPUP_H)
    popup:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
    popup:SetFrameStrata("DIALOG"); popup:SetFrameLevel(510)
    popup:EnableMouse(true); popup:SetMovable(true); popup:SetClampedToScreen(true)
    popup:RegisterForDrag("LeftButton")
    popup:SetScript("OnDragStart", function(self) self:StartMoving() end)
    popup:SetScript("OnDragStop",  function(self) self:StopMovingOrSizing() end)
    SolidTex(popup, "BACKGROUND", POPUP_MAIN_BG[1], POPUP_MAIN_BG[2], POPUP_MAIN_BG[3], POPUP_MAIN_BG[4]):SetAllPoints()
    MakeBorder(popup, 0.7, 0.7, 0.75, 0.25)

    local title = MakeFont(popup, 15, nil, 1, 1, 1)
    title:SetPoint("TOPLEFT", popup, "TOPLEFT", 16, -14)
    title:SetText("EllesmereUI 추가 기능")
    local sub = MakeFont(popup, 10, nil, 0.7, 0.7, 0.7, 0.6)
    sub:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -4)
    sub:SetText("|cff0091ed엘스미어 한글|r 에서 제공")

    -- 우상단: 팝업 크기
    local function ApplyPopupScale()
        local s = GetDB().popupScale or 1.0
        if s < POPUP_SCALE_MIN then s = POPUP_SCALE_MIN end
        if s > POPUP_SCALE_MAX then s = POPUP_SCALE_MAX end
        popup:SetScale(s)
    end
    local scaleRow = CreateFrame("Frame", nil, popup)
    scaleRow:SetSize(140, 22)
    scaleRow:SetPoint("TOPRIGHT", popup, "TOPRIGHT", -10, -10)
    SolidTex(scaleRow, "BACKGROUND", POPUP_STEP_BG[1], POPUP_STEP_BG[2], POPUP_STEP_BG[3], POPUP_STEP_BG[4]):SetAllPoints()
    local scaleVal = MakeFont(scaleRow, 11, nil, 0.62, 0.62, 0.68)
    scaleVal:SetPoint("CENTER")
    local function UpdateScaleText() scaleVal:SetText(string.format("크기 %.1fx", GetDB().popupScale or 1.0)) end
    MakeStepBtn(scaleRow, "LEFT",  "◀", function()
        local db = GetDB(); db.popupScale = math.max(POPUP_SCALE_MIN, (db.popupScale or 1.0) - POPUP_SCALE_STEP)
        ApplyPopupScale(); UpdateScaleText()
    end)
    MakeStepBtn(scaleRow, "RIGHT", "▶", function()
        local db = GetDB(); db.popupScale = math.min(POPUP_SCALE_MAX, (db.popupScale or 1.0) + POPUP_SCALE_STEP)
        ApplyPopupScale(); UpdateScaleText()
    end)
    UpdateScaleText()

    popup:HookScript("OnShow", function(self)
        self:ClearAllPoints()
        self:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
        ApplyPopupScale()
        for _, fn in ipairs(NS._onShow) do pcall(fn) end
    end)

    -- 등록 섹션 배치 (col/row 명시 우선, 미지정 시 2열 플로우 폴백)
    local flowN = 0
    for _, sec in ipairs(secs) do
        local col, rowIdx
        if sec.col ~= nil or sec.row ~= nil then
            col = sec.col or 0
            rowIdx = sec.row or 0
        else
            col = flowN % 2
            rowIdx = math.floor(flowN / 2)
            flowN = flowN + 1
        end
        local x = (col == 0) and 20 or COL2_X
        local y = sectionY - rowIdx * 90
        local hdr = MakeFont(popup, 13, nil, 0.73, 0.73, 0.73)
        hdr:SetPoint("TOPLEFT", popup, "TOPLEFT", x, y)
        hdr:SetText(sec.title or "")
        _div(popup, hdr, COL_W)
        local desc = MakeDescFS(popup, 11, 0.6, 0.6, 0.65)
        desc:SetPoint("TOPLEFT", hdr, "BOTTOMLEFT", 0, -10)
        desc:SetWordWrap(false)
        desc:SetText(sec.desc or "")
        if type(sec.build) == "function" then pcall(sec.build, popup, desc) end
    end

    -- 하단: 닫기 / 설정 초기화 / 진단
    local closeBtn = CreateFrame("Button", nil, popup)
    closeBtn:SetSize(100, 26)
    closeBtn:SetPoint("BOTTOM", popup, "BOTTOM", 0, 16)
    local closeBg = SolidTex(closeBtn, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
    closeBg:SetAllPoints()
    MakeBorder(closeBtn, 0.30, 0.40, 0.50, 0.6)
    local closeLbl = MakeFont(closeBtn, 12, "OUTLINE", 1, 1, 1)
    closeLbl:SetPoint("CENTER"); closeLbl:SetText("닫기")
    closeBtn:SetScript("OnEnter", function() closeBg:SetColorTexture(0.25, 0.55, 0.85, 0.95) end)
    closeBtn:SetScript("OnLeave", function() closeBg:SetColorTexture(POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4]) end)
    closeBtn:SetScript("OnClick", function() dimmer:Hide() end)

    local resetBtn = CreateFrame("Button", nil, popup)
    resetBtn:SetSize(140, 26)
    resetBtn:SetPoint("BOTTOM", popup, "BOTTOM", 150, 16)
    local resetBg = SolidTex(resetBtn, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
    resetBg:SetAllPoints()
    MakeBorder(resetBtn, 0.7, 0.5, 0.5, 0.6)
    local resetLbl = MakeFont(resetBtn, 12, "OUTLINE", 1, 0.9, 0.9)
    resetLbl:SetPoint("CENTER"); resetLbl:SetText("설정 초기화")
    resetBtn:SetScript("OnEnter", function() resetBg:SetColorTexture(0.65, 0.25, 0.25, 0.95) end)
    resetBtn:SetScript("OnLeave", function() resetBg:SetColorTexture(POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4]) end)
    resetBtn:SetScript("OnClick", function()
        if EllesmereUI and type(EllesmereUI.ShowConfirmPopup) == "function" then
            EllesmereUI:ShowConfirmPopup({
                title = "추가기능 설정 초기화",
                message = "추가기능 설정을 모두 초기화하고 /reload 합니다.\n계속하시겠습니까?",
                confirmText = "확인", cancelText = "취소",
                onConfirm = function() EllesmereUIKorAdditionsDB = {}; ReloadUI() end,
            })
        else
            EllesmereUIKorAdditionsDB = {}; ReloadUI()
        end
    end)

    local diagBtn = CreateFrame("Button", nil, popup)
    diagBtn:SetSize(100, 26)
    diagBtn:SetPoint("BOTTOM", popup, "BOTTOM", -150, 16)
    local diagBg = SolidTex(diagBtn, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
    diagBg:SetAllPoints()
    MakeBorder(diagBtn, 0.5, 0.7, 0.5, 0.6)
    local diagLbl = MakeFont(diagBtn, 12, "OUTLINE", 0.9, 1, 0.9)
    diagLbl:SetPoint("CENTER"); diagLbl:SetText("진단")
    diagBtn:SetScript("OnEnter", function() diagBg:SetColorTexture(0.25, 0.55, 0.30, 0.95) end)
    diagBtn:SetScript("OnLeave", function() diagBg:SetColorTexture(POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4]) end)
    diagBtn:SetScript("OnClick", function() NS.ShowDiag() end)

    return popup, dimmer
end
NS.CreatePopup = CreatePopup

local function TogglePopup()
    local _, dimmer = CreatePopup()
    if dimmer:IsShown() then dimmer:Hide() else dimmer:Show() end
end
NS.TogglePopup = TogglePopup

-- ============================================================
--  진단창 (lazy 싱글톤). 기능 내부는 _G + pcall + nil 가드로만 참조.
-- ============================================================
local _diagFrame
local function _BuildDiagText()
    local lines, issues = {}, {}
    local function add(s) lines[#lines + 1] = s end
    local function ok_(v) return v and "있음" or "없음" end
    local function chk(label, isOk, val, badMeans)
        add(string.format("  %s  %s = %s", isOk and "✅" or "❌", label, tostring(val)))
        if not isOk then issues[#issues + 1] = string.format("• %s — 현재값=%s — %s", label, tostring(val), badMeans or "") end
    end
    local db = GetDB()
    add("════════ EllesmereUI_koKR_Plus 진단 ════════")
    add("(✅ 정상 / ❌ 비정상. 미로드 기능은 섹션 자체가 생략됨 = 사용량 0.)")
    add("")
    add("[1. 환경]")
    chk("로케일=koKR", GetLocale() == "koKR", GetLocale(), "koKR 아니면 한글화 미동작")
    chk("EllesmereUI 로드", _G.EllesmereUI ~= nil, ok_(_G.EllesmereUI), "원본 미설치/비활성")
    chk("EUI._mainFrame", _G.EllesmereUI and _G.EllesmereUI._mainFrame ~= nil,
        ok_(_G.EllesmereUI and _G.EllesmereUI._mainFrame), "EUI 메인프레임 없음 → 옵션창 못 엶")
    add(string.format("  ℹ  WoW=%s  전투중=%s", select(1, GetBuildInfo()), tostring(InCombatLockdown())))
    add("")
    add("[2. SavedVariables (nil = DB 머지 실패)]")
    for _, k in ipairs({ "widgetScale","settingsTipScale","popupScale","npExtraY",
        "charSheetScale","inspectScale","eqsetIcon","hotkeyShorten","cdmHotkeyShorten" }) do
        chk(k, db[k] ~= nil, db[k], "nil = DB 머지 실패")
    end
    add("")
    add("[3. 등록 현황 (로드된 기능만)]")
    add(string.format("  ℹ  등록 섹션=%d  설치후크=%d  진단제공=%d",
        #NS._sections, #NS._installs, #NS._diags))
    chk("EUI_L 번역 테이블", type(_G.EUI_L) == "table", type(_G.EUI_L), "Locale 미로드 → 영문")
    -- 분리 도메인 addon
    local function isLoaded(n)
        if C_AddOns and C_AddOns.IsAddOnLoaded then return (C_AddOns.IsAddOnLoaded(n)) end
        return IsAddOnLoaded and IsAddOnLoaded(n)
    end
    if isLoaded("EllesmereUI_koKR_Plus") then
        local cdb = _G.EllesmereUIKorCastbarDB
        local mdb = _G.EllesmereUIKorMinimapPinDB
        add("")
        add("[3.5 도메인 DB]")
        add(string.format("  ℹ  CastbarDB=%s  MinimapPinDB=%s", type(cdb), type(mdb)))
    end
    -- 기능별 진단 (등록된 것만)
    if #NS._diags > 0 then
        add("")
        add("[4. 기능별]")
        for _, fn in ipairs(NS._diags) do pcall(fn, add, chk) end
    end
    add("")
    add("══════════════ 문제 요약 ══════════════")
    if #issues == 0 then add("  ✅ 모든 핵심 점검 통과.")
    else add(string.format("  ❌ %d 개 문제:", #issues)); for _, m in ipairs(issues) do add("  " .. m) end end
    add("══════════════════════════════════════")
    return table.concat(lines, "\n")
end

function NS.ShowDiag()
    local text = _BuildDiagText()
    if not _diagFrame then
        local f = CreateFrame("Frame", "CIMKRPlusDiag", UIParent, "BackdropTemplate")
        _diagFrame = f
        f:SetSize(620, 480); f:SetPoint("CENTER")
        f:SetFrameStrata("FULLSCREEN_DIALOG"); f:SetFrameLevel(300)
        f:EnableMouse(true); f:SetClampedToScreen(true); f:SetMovable(true)
        f:RegisterForDrag("LeftButton")
        f:SetScript("OnDragStart", f.StartMoving); f:SetScript("OnDragStop", f.StopMovingOrSizing)
        tinsert(UISpecialFrames, "CIMKRPlusDiag")
        SolidTex(f, "BACKGROUND", 0.06, 0.08, 0.10, 0.97):SetAllPoints()
        MakeBorder(f, 0.5, 0.7, 0.5, 0.8)
        local t = MakeFont(f, 14, "OUTLINE", 0.85, 1, 0.85)
        t:SetPoint("TOP", f, "TOP", 0, -12); t:SetText("EllesmereUI_koKR_Plus 진단")
        local sf = CreateFrame("ScrollFrame", "$parentSF", f, "UIPanelScrollFrameTemplate")
        sf:SetPoint("TOPLEFT", f, "TOPLEFT", 14, -40)
        sf:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -34, 50)
        local eb = CreateFrame("EditBox", nil, sf)
        eb:SetMultiLine(true); eb:SetAutoFocus(false); eb:SetFontObject("ChatFontNormal"); eb:SetWidth(560)
        eb:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
        sf:SetScrollChild(eb); f._eb = eb
        local copyBtn = CreateFrame("Button", nil, f)
        copyBtn:SetSize(120, 24); copyBtn:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 16, 12)
        local copyBg = SolidTex(copyBtn, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
        copyBg:SetAllPoints()
        MakeBorder(copyBtn, 0.5, 0.8, 0.5, 0.6)
        local copyLbl = MakeFont(copyBtn, 12, "OUTLINE", 0.9, 1, 0.9)
        copyLbl:SetPoint("CENTER"); copyLbl:SetText("복사 (Ctrl+C)")
        copyBtn:SetScript("OnClick", function() f._eb:SetFocus(); f._eb:HighlightText() end)
        local rB = CreateFrame("Button", nil, f)
        rB:SetSize(80, 24); rB:SetPoint("LEFT", copyBtn, "RIGHT", 8, 0)
        local rBg = SolidTex(rB, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
        rBg:SetAllPoints()
        local rLbl = MakeFont(rB, 12, "OUTLINE", 1, 1, 1); rLbl:SetPoint("CENTER"); rLbl:SetText("새로고침")
        rB:SetScript("OnClick", function() f._eb:SetText(_BuildDiagText()) end)
        local cb = CreateFrame("Button", nil, f)
        cb:SetSize(80, 24); cb:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -16, 12)
        local cbBg = SolidTex(cb, "BACKGROUND", POPUP_BTN_BG[1], POPUP_BTN_BG[2], POPUP_BTN_BG[3], POPUP_BTN_BG[4])
        cbBg:SetAllPoints()
        local cbLbl = MakeFont(cb, 12, "OUTLINE", 1, 1, 1); cbLbl:SetPoint("CENTER"); cbLbl:SetText("닫기")
        cb:SetScript("OnClick", function() f:Hide() end)
    end
    _diagFrame._eb:SetText(text)
    _diagFrame:Show()
end

-- ============================================================
--  EUI 메인프레임 우상단 "추가 기능" 버튼 + 진입점
-- ============================================================
local function InstallMainFrameButton()
    local mf = EllesmereUI and EllesmereUI._mainFrame
    if not mf or mf.__cimAdditionsBtn then return end
    local clickArea = _G.EllesmereUIClickArea
    if not clickArea then return end
    local btn = CreateFrame("Button", nil, clickArea)
    btn:SetSize(76, 38)
    btn:SetPoint("TOPRIGHT", clickArea, "TOPRIGHT", -59, -11)
    btn:SetFrameLevel(clickArea:GetFrameLevel() + 21)
    mf.__cimAdditionsBtn = btn
    local bg = SolidTex(btn, "BACKGROUND", 0.18, 0.22, 0.30, 0.55)
    bg:SetAllPoints()
    local borders = MakeBorder(btn, 0.65, 0.78, 0.95, 0.75)
    local fs = btn:CreateFontString(nil, "OVERLAY")
    fs:SetFont(GetFont(), 13, "OUTLINE"); fs:SetPoint("CENTER")
    fs:SetText("|cffffffff추가 기능|r")
    btn:SetScript("OnEnter", function()
        bg:SetColorTexture(0.28, 0.42, 0.65, 0.85)
        SetBorderColor(borders, 0.85, 0.92, 1.0, 1)
        GameTooltip:SetOwner(btn, "ANCHOR_TOP")
        GameTooltip:AddLine("EllesmereUI 한글 추가 기능", 1, 1, 1)
        GameTooltip:AddLine("엘스미어에 없는 추가 옵션을 설정합니다.", 0.85, 0.85, 0.85, true)
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function()
        bg:SetColorTexture(0.18, 0.22, 0.30, 0.55)
        SetBorderColor(borders, 0.65, 0.78, 0.95, 0.75)
        GameTooltip:Hide()
    end)
    btn:SetScript("OnClick", TogglePopup)
end

local function TryInstallButton()
    if not (EllesmereUI and EllesmereUI._mainFrame and _G.EllesmereUIClickArea) then return false end
    local mf, clickArea = EllesmereUI._mainFrame, _G.EllesmereUIClickArea
    -- EUI 옵션창을 열거나 페이지 전환할 때마다 버튼 재부착 (clickArea 재생성 대응).
    -- 지연 재확인(0.05/0.2s)으로 clickArea 가 늦게 생겨도 잡음. 상시 폴링 아님.
    local EUI = _G.EllesmereUI
    if EUI and not EUI.__cimPlusPanelReattach then
        EUI.__cimPlusPanelReattach = true
        local function deferred()
            TryInstallButton()
            if C_Timer and C_Timer.After then
                C_Timer.After(0.05, TryInstallButton)
                C_Timer.After(0.20, TryInstallButton)
            end
        end
        if type(EUI.Show)        == "function" then hooksecurefunc(EUI, "Show",        deferred) end
        if type(EUI.Toggle)      == "function" then hooksecurefunc(EUI, "Toggle",      deferred) end
        if type(EUI.SelectPage)  == "function" then hooksecurefunc(EUI, "SelectPage",  deferred) end
        if type(EUI.RefreshPage) == "function" then hooksecurefunc(EUI, "RefreshPage", deferred) end
    end
    -- 패널이 *열려 있는 동안만* 0.3초마다 버튼 확인 → 항상 보이게 보장. 닫으면 OnUpdate 안 돎(사용량 0).
    if mf.HookScript and not mf.__cimPlusBtnOnUpdate then
        mf.__cimPlusBtnOnUpdate = true
        local acc = 0
        mf:HookScript("OnUpdate", function(_, elapsed)
            acc = acc + (elapsed or 0)
            if acc < 0.3 then return end
            acc = 0
            TryInstallButton()
        end)
    end
    local btn = mf.__cimAdditionsBtn
    if btn and btn.GetParent and btn:GetParent() == clickArea then
        if btn.IsShown and not btn:IsShown() and btn.Show then btn:Show() end
        return true
    end
    mf.__cimAdditionsBtn = nil
    InstallMainFrameButton()
    return mf.__cimAdditionsBtn ~= nil
end

local _initialApplied = false
-- 모든 install 콜백 실행. 각 콜백은 가드/idempotent 라 여러 번 불러도 안전(1회만 실효).
local function RunInstalls()
    if not EllesmereUI then return end
    for _, fn in ipairs(NS._installs) do pcall(fn) end
end
local function ApplyInitial()
    if _initialApplied or not EllesmereUI then return end
    RunInstalls()
    _initialApplied = true
end
NS.ApplyInitial = ApplyInitial

-- ★ 접속 직후 배율 자동 적용:
--   로그인 시점엔 EUI 가 GetPopupScale / ShowWidgetTooltip 같은 위젯 함수를 *아직
--   정의 전*일 수 있어 배율 wrap·후크가 안 걸린다 → 그래서 지금까진 "설정창을 한 번
--   열어야(또는 수치 조정해야) 배율이 먹는" 증상이 있었다. EUI 위젯 함수가 준비될
--   때까지 install 을 짧게 재시도하면, 설정창을 안 열어도 접속하자마자 위젯/툴팁/
--   캐릭터창 등 *모든 배율* 이 적용된다. 준비가 확인되면 티커를 끈다.
local function _EUIScaleReady()
    local E = _G.EllesmereUI
    return E ~= nil
        and type(E.GetPopupScale) == "function"
        and type(E.ShowWidgetTooltip) == "function"
end
local function _StartInstallRetry()
    if not (C_Timer and C_Timer.NewTicker) then RunInstalls(); return end
    local n, okStreak = 0, 0
    C_Timer.NewTicker(0.3, function(tk)
        n = n + 1
        RunInstalls()                                    -- 매 틱 재시도(가드로 안전)
        if _EUIScaleReady() then okStreak = okStreak + 1 else okStreak = 0 end
        if okStreak >= 2 or n >= 40 then tk:Cancel() end -- 준비 2틱 연속 또는 ~12초 후 종료
    end)
end

-- 이벤트 배선
local _btnTicker
local ef = CreateFrame("Frame")
ef:RegisterEvent("PLAYER_LOGIN")
ef:RegisterEvent("PLAYER_ENTERING_WORLD")        -- 리로드/구역 이동 후 배율 재확정(idempotent)
ef:SetScript("OnEvent", function(_, evt)
    if evt == "PLAYER_ENTERING_WORLD" then RunInstalls(); return end
    _dbReady = false; GetDB(); _dbReady = true   -- SV 복원 후 누락 키 머지 + 잠금
    ApplyInitial()
    _StartInstallRetry()                          -- ★ EUI 준비될 때까지 배율 재시도(설정창 불필요)
    if C_Timer and C_Timer.NewTicker then
        local tries = 0
        _btnTicker = C_Timer.NewTicker(0.5, function(tk)
            tries = tries + 1
            local mf2 = EllesmereUI and EllesmereUI._mainFrame
            if mf2 and mf2.HookScript and not mf2.__cimAddBtnShowHook then
                mf2.__cimAddBtnShowHook = true
                pcall(mf2.HookScript, mf2, "OnShow", TryInstallButton)
            end
            local ca2 = _G.EllesmereUIClickArea
            if ca2 and ca2.HookScript and not ca2.__cimAddBtnShowHook then
                ca2.__cimAddBtnShowHook = true
                pcall(ca2.HookScript, ca2, "OnShow", TryInstallButton)
            end
            if TryInstallButton() or tries > 1200 then
                tk:Cancel(); _btnTicker = nil
            end
        end)
    end
end)
