local addonTable = select(2, ...)
---@type MK
local MK = addonTable.MK
local core = addonTable
local TRANSLATE = core.TRANSLATE or function(msg) return msg end

core.MeetingStoneForm = core.MeetingStoneForm or {}
local MeetingStoneForm = core.MeetingStoneForm
local MeetingStoneConstants = core.MeetingStoneConstants or {}
local MEETINGSTONE_PLAY_STYLE_OPTIONS = MeetingStoneConstants.MEETINGSTONE_PLAY_STYLE_OPTIONS
local MEETINGSTONE_SYSTEM_BUTTON_TEMPLATE = MeetingStoneConstants.MEETINGSTONE_SYSTEM_BUTTON_TEMPLATE
local MEETINGSTONE_FORM_LABEL_TEXT_SIZE = MeetingStoneConstants.MEETINGSTONE_FORM_LABEL_TEXT_SIZE
local MEETINGSTONE_FORM_LABEL_TEXT_COLOR = MeetingStoneConstants.MEETINGSTONE_FORM_LABEL_TEXT_COLOR
local MEETINGSTONE_FORM_INPUT_BACKGROUND_COLOR = MeetingStoneConstants.MEETINGSTONE_FORM_INPUT_BACKGROUND_COLOR
local MEETINGSTONE_FORM_INPUT_BORDER_ATLAS = MeetingStoneConstants.MEETINGSTONE_FORM_INPUT_BORDER_ATLAS
local MEETINGSTONE_FORM_TITLE_BORDER_ATLAS = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_BORDER_ATLAS
local MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_LEFT = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_LEFT
local MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_TOP = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_TOP
local MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_RIGHT = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_RIGHT
local MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_BOTTOM = MeetingStoneConstants.MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_BOTTOM
local MEETINGSTONE_FORM_TEXTAREA_INNER_BORDER_COLOR = MeetingStoneConstants.MEETINGSTONE_FORM_TEXTAREA_INNER_BORDER_COLOR
local MEETINGSTONE_FORM_TEXTAREA_MIDDLE_BORDER_COLOR = MeetingStoneConstants.MEETINGSTONE_FORM_TEXTAREA_MIDDLE_BORDER_COLOR
local MEETINGSTONE_FORM_TEXTAREA_OUTER_GAP = MeetingStoneConstants.MEETINGSTONE_FORM_TEXTAREA_OUTER_GAP
local MEETINGSTONE_FORM_TEXTAREA_BORDER_SIZE = MeetingStoneConstants.MEETINGSTONE_FORM_TEXTAREA_BORDER_SIZE
local MEETINGSTONE_FORM_TEXTAREA_ROUND_EDGE_SIZE = MeetingStoneConstants.MEETINGSTONE_FORM_TEXTAREA_ROUND_EDGE_SIZE
local MEETINGSTONE_FORM_TEXTAREA_MIDDLE_ROUND_EDGE_SIZE = MeetingStoneConstants.MEETINGSTONE_FORM_TEXTAREA_MIDDLE_ROUND_EDGE_SIZE
local MEETINGSTONE_FORM_BUTTON_TEXT_SIZE = MeetingStoneConstants.MEETINGSTONE_FORM_BUTTON_TEXT_SIZE
local MeetingStoneBridge = core.MeetingStoneBridge or {}
local MeetingStoneListing = core.MeetingStoneListing or {}

local ApplyMeetingStoneSummaryTextInsets = MeetingStoneBridge.ApplySummaryTextInsets
local GetMeetingStoneDefaultPlayStyle = MeetingStoneListing.GetDefaultPlayStyle
local GetMeetingStonePlayStyleText = MeetingStoneListing.GetPlayStyleText
local GetMeetingStonePlayStyleValue = MeetingStoneListing.GetPlayStyleValue
local IsMeetingStonePlayStyleValueEqual = MeetingStoneListing.IsPlayStyleValueEqual

local function TrySetMeetingStoneAtlas(texture, atlas, useAtlasSize)
    if not texture or not atlas then
        return false
    end

    if core.TrySetAtlas and core.TrySetAtlas(texture, atlas, useAtlasSize) then
        return true
    end

    if not texture.SetAtlas then
        return false
    end

    local ok = pcall(texture.SetAtlas, texture, atlas, useAtlasSize)
    return ok == true
end

local function CreateMeetingStoneLabel(parent, text)
    local label = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    label:SetText(text)
    label:SetJustifyH("LEFT")
    label:SetJustifyV("MIDDLE")
    if label.SetWordWrap then
        label:SetWordWrap(false)
    end
    label:SetTextColor(
        MEETINGSTONE_FORM_LABEL_TEXT_COLOR[1],
        MEETINGSTONE_FORM_LABEL_TEXT_COLOR[2],
        MEETINGSTONE_FORM_LABEL_TEXT_COLOR[3],
        MEETINGSTONE_FORM_LABEL_TEXT_COLOR[4]
    )
    if core.ApplyFont then
        core.ApplyFont(label, MEETINGSTONE_FORM_LABEL_TEXT_SIZE, "")
    end
    return label
end

local function AddMeetingStoneInputBackground(editBox)
    if not editBox or editBox.mkMeetingStoneInputBackground then
        return
    end

    local background = editBox:CreateTexture(nil, "BACKGROUND", nil, -2)
    background:SetPoint("TOPLEFT", editBox, "TOPLEFT", 0, -2)
    background:SetPoint("BOTTOMRIGHT", editBox, "BOTTOMRIGHT", 0, 2)
    background:SetTexture("Interface\\Buttons\\WHITE8X8")
    background:SetVertexColor(
        MEETINGSTONE_FORM_INPUT_BACKGROUND_COLOR[1],
        MEETINGSTONE_FORM_INPUT_BACKGROUND_COLOR[2],
        MEETINGSTONE_FORM_INPUT_BACKGROUND_COLOR[3],
        MEETINGSTONE_FORM_INPUT_BACKGROUND_COLOR[4]
    )

    local border = editBox:CreateTexture(nil, "BORDER", nil, -1)
    border:SetPoint("TOPLEFT", editBox, "TOPLEFT", -8, 7)
    border:SetPoint("BOTTOMRIGHT", editBox, "BOTTOMRIGHT", 8, -9)
    if border.SetAtlas then
        border:SetAtlas(MEETINGSTONE_FORM_INPUT_BORDER_ATLAS, false)
    else
        border:SetTexture("Interface\\Buttons\\WHITE8X8")
        border:SetVertexColor(1, 1, 1, 0.14)
    end

    editBox.mkMeetingStoneInputBackground = background
    editBox.mkMeetingStoneInputBorder = border
end

local DisableMeetingStoneFrameMouse

local function AddMeetingStoneTextAreaBorderLayer(frame, offset, color, edgeSize)
    local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
    border:SetPoint("TOPLEFT", frame, "TOPLEFT", -offset, offset)
    border:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", offset, -offset)
    border:SetFrameLevel(frame:GetFrameLevel() + 1)
    DisableMeetingStoneFrameMouse(border)
    if border.SetBackdrop then
        border:SetBackdrop({
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            edgeSize = edgeSize or MEETINGSTONE_FORM_TEXTAREA_ROUND_EDGE_SIZE,
            insets = { left = 0, right = 0, top = 0, bottom = 0 },
        })
        border:SetBackdropBorderColor(color[1], color[2], color[3], color[4])
    end

    return border
end

local function AddMeetingStoneTextAreaBackground(frame)
    if not frame or frame.mkMeetingStoneTextAreaBackground then
        return
    end

    local innerBorder = AddMeetingStoneTextAreaBorderLayer(frame, 0, MEETINGSTONE_FORM_TEXTAREA_INNER_BORDER_COLOR)
    local middleOffset = MEETINGSTONE_FORM_TEXTAREA_BORDER_SIZE + MEETINGSTONE_FORM_TEXTAREA_OUTER_GAP
    local middleBorder = AddMeetingStoneTextAreaBorderLayer(frame, middleOffset, MEETINGSTONE_FORM_TEXTAREA_MIDDLE_BORDER_COLOR, MEETINGSTONE_FORM_TEXTAREA_MIDDLE_ROUND_EDGE_SIZE)

    frame.mkMeetingStoneTextAreaInnerBorder = innerBorder
    frame.mkMeetingStoneTextAreaMiddleBorder = middleBorder
    frame.mkMeetingStoneTextAreaBackground = true
end

DisableMeetingStoneFrameMouse = function(frame)
    if not frame then
        return
    end
    if frame.EnableMouse then
        frame:EnableMouse(false)
    end
    if frame.EnableMouseWheel then
        frame:EnableMouseWheel(false)
    end
    if frame.SetMouseClickEnabled then
        pcall(frame.SetMouseClickEnabled, frame, false)
    end
    if frame.SetMouseMotionEnabled then
        pcall(frame.SetMouseMotionEnabled, frame, false)
    end
end

local function AddMeetingStoneTitleHolderBorder(holder)
    if not holder or holder.mkMeetingStoneTitleBorder then
        return
    end

    local border = holder:CreateTexture(nil, "OVERLAY", nil, 7)
    border:SetPoint("TOPLEFT", holder, "TOPLEFT", MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_LEFT, MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_TOP)
    border:SetPoint("BOTTOMRIGHT", holder, "BOTTOMRIGHT", MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_RIGHT, MEETINGSTONE_FORM_TITLE_BORDER_OFFSET_BOTTOM)
    if border.SetAtlas then
        border:SetAtlas(MEETINGSTONE_FORM_TITLE_BORDER_ATLAS, false)
    else
        border:SetTexture("Interface\\Buttons\\WHITE8X8")
        border:SetVertexColor(1, 1, 1, 0.14)
    end

    holder.mkMeetingStoneTitleBorder = border
end

local function HideMeetingStoneFrameRegion(region)
    if not region or not region.Hide then
        return
    end
    region:Hide()
    if region.SetAlpha then
        region:SetAlpha(0)
    end
end

local function HideMeetingStoneInputBoxChrome(editBox)
    if not editBox then
        return
    end

    local name = editBox.GetName and editBox:GetName()
    if name then
        for _, region in ipairs({
            _G[name .. "Left"],
            _G[name .. "Middle"],
            _G[name .. "Right"],
            _G[name .. "LeftTexture"],
            _G[name .. "MiddleTexture"],
            _G[name .. "RightTexture"],
        }) do
            HideMeetingStoneFrameRegion(region)
        end
    end

    HideMeetingStoneFrameRegion(editBox.Left)
    HideMeetingStoneFrameRegion(editBox.Middle)
    HideMeetingStoneFrameRegion(editBox.Right)
    HideMeetingStoneFrameRegion(editBox.LeftTexture)
    HideMeetingStoneFrameRegion(editBox.MiddleTexture)
    HideMeetingStoneFrameRegion(editBox.RightTexture)
end

local function StyleMeetingStoneInputBox(editBox)
    if not editBox or editBox._mkMeetingStoneInputStyled then
        return
    end

    if core.ApplyFont then
        core.ApplyFont(editBox, 12, "")
    end
    editBox:SetTextColor(1, 0.96, 0.86, 1)
    editBox:SetShadowColor(0, 0, 0, 0.8)
    editBox:SetShadowOffset(1, -1)
    if editBox.SetTextInsets then
        editBox:SetTextInsets(10, 10, 0, 0)
    end

    HideMeetingStoneInputBoxChrome(editBox)

    editBox:SetScript("OnEditFocusGained", function(self)
        self:HighlightText(0, 0)
        self:SetCursorPosition(strlen(self:GetText() or ""))
    end)

    AddMeetingStoneInputBackground(editBox)
    editBox._mkMeetingStoneInputStyled = true
end

local function CreateMeetingStoneInput(parent, width, height, numeric)
    local editBox = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
    editBox:SetSize(width, height or 24)
    editBox:SetAutoFocus(false)
    if numeric then
        editBox:SetNumeric(true)
    end
    StyleMeetingStoneInputBox(editBox)
    return editBox
end

local function RefreshMeetingStoneInputPlaceholder(editBox)
    local placeholder = editBox and editBox.mkMeetingStonePlaceholder
    if not placeholder then
        return
    end

    local text = editBox.GetText and editBox:GetText() or ""
    if text == "" then
        placeholder:Show()
    else
        placeholder:Hide()
    end
end

local function SetMeetingStoneInputPlaceholder(editBox, text, multiline)
    if not (editBox and editBox.CreateFontString) then
        return
    end

    local placeholder = editBox.mkMeetingStonePlaceholder
    if not placeholder then
        placeholder = editBox:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
        placeholder:SetTextColor(0.58, 0.56, 0.52, 0.95)
        placeholder:SetJustifyH("LEFT")
        placeholder:SetWordWrap(multiline == true)
        placeholder:ClearAllPoints()
        if multiline then
            placeholder:SetPoint("TOPLEFT", editBox, "TOPLEFT", 0, -1)
            placeholder:SetPoint("RIGHT", editBox, "RIGHT", 0, 0)
            placeholder:SetJustifyV("TOP")
        else
            placeholder:SetPoint("LEFT", editBox, "LEFT", 10, 0)
            placeholder:SetPoint("RIGHT", editBox, "RIGHT", -10, 0)
            placeholder:SetJustifyV("MIDDLE")
        end
        editBox.mkMeetingStonePlaceholder = placeholder
    end

    placeholder:SetText(text or "")
    if not editBox.mkMeetingStonePlaceholderHooked then
        editBox:HookScript("OnTextChanged", RefreshMeetingStoneInputPlaceholder)
        editBox:HookScript("OnEditFocusGained", RefreshMeetingStoneInputPlaceholder)
        editBox:HookScript("OnEditFocusLost", RefreshMeetingStoneInputPlaceholder)
        editBox.mkMeetingStonePlaceholderHooked = true
    end
    RefreshMeetingStoneInputPlaceholder(editBox)
end

local function SelectAllMeetingStoneInputText(editBox)
    if not editBox or not editBox.HighlightText then
        return
    end

    local text = editBox.GetText and editBox:GetText() or ""
    editBox:HighlightText(0, strlen(text or ""))
end

local function EnableMeetingStoneSelectAllAfterMouseLeave(editBox)
    if not editBox or editBox._mkSelectAllAfterMouseLeave then
        return
    end

    editBox._mkSelectAllOnNextClick = true
    editBox:HookScript("OnEditFocusGained", function(self)
        self._mkSelectAllOnNextClick = nil
        SelectAllMeetingStoneInputText(self)
    end)
    editBox:HookScript("OnLeave", function(self)
        self._mkSelectAllOnNextClick = true
    end)
    editBox:HookScript("OnMouseUp", function(self)
        if self._mkSelectAllOnNextClick then
            self._mkSelectAllOnNextClick = nil
            SelectAllMeetingStoneInputText(self)
        end
    end)
    editBox._mkSelectAllAfterMouseLeave = true
end

local function CreateMeetingStoneSummaryBox(parent, width, height)
    local frame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    frame:SetSize(width, height)
    AddMeetingStoneTextAreaBackground(frame)

    local editBox = CreateFrame("EditBox", nil, frame)
    ApplyMeetingStoneSummaryTextInsets(editBox, frame)
    editBox:SetAutoFocus(false)
    editBox:SetMultiLine(true)
    editBox:SetMaxLetters(280)
    if core.ApplyFont then
        core.ApplyFont(editBox, 12, "")
    else
        editBox:SetFontObject("GameFontHighlight")
    end
    editBox:SetTextColor(1, 0.96, 0.86, 1)
    editBox:SetShadowColor(0, 0, 0, 0.8)
    editBox:SetShadowOffset(1, -1)
    editBox:SetJustifyH("LEFT")
    editBox:SetJustifyV("TOP")
    return frame, editBox
end

local function ApplyMeetingStoneSystemButtonStyle(button)
    if not button then
        return
    end

    if button.SetNormalFontObject then
        button:SetNormalFontObject("GameFontNormalSmall")
    end
    if button.SetHighlightFontObject then
        button:SetHighlightFontObject("GameFontHighlightSmall")
    end
    if button.SetDisabledFontObject then
        button:SetDisabledFontObject("GameFontDisableSmall")
    end

    if core.ApplyFont then
        local fontString = button.Text or (button.GetFontString and button:GetFontString())
        core.ApplyFont(fontString, MEETINGSTONE_FORM_BUTTON_TEXT_SIZE, "")
    end
    if core.MeetingStoneButtonArt and core.MeetingStoneButtonArt.Apply then
        core.MeetingStoneButtonArt.Apply(button)
    end
end

local function SetMeetingStoneSystemButtonTextOffset(button, offsetY)
    local fontString = button and (button.Text or (button.GetFontString and button:GetFontString()))
    if not fontString then
        return
    end

    if button.mkMeetingStoneButtonArtApplied then
        offsetY = 0
    end
    fontString:ClearAllPoints()
    fontString:SetPoint("CENTER", button, "CENTER", 0, offsetY or 0)
    if fontString.SetJustifyH then
        fontString:SetJustifyH("CENTER")
    end
    if fontString.SetJustifyV then
        fontString:SetJustifyV("MIDDLE")
    end
end

local function CreateMeetingStoneSystemButton(parent, name, width, height, text, textOffsetY)
    local button = CreateFrame("Button", name, parent, MEETINGSTONE_SYSTEM_BUTTON_TEMPLATE)
    button:SetSize(width, height)
    if text then
        button:SetText(text)
    end
    ApplyMeetingStoneSystemButtonStyle(button)
    if textOffsetY then
        SetMeetingStoneSystemButtonTextOffset(button, textOffsetY)
    end
    return button
end

local function GetMeetingStoneDungeonDropdownText(owner)
    local draft = owner and owner.meetingStoneDraft
    if draft and draft.activityName and draft.activityName ~= "" then
        return draft.activityName
    end
    return TRANSLATE("选择赛季副本")
end

local function GetMeetingStoneDungeonOptionText(option)
    return option and option.activityName or ""
end

local function IsMeetingStoneDungeonOptionSelected(draft, option)
    if not draft or not option then
        return false
    end
    if draft.activityID and option.activityID then
        return tonumber(draft.activityID) == tonumber(option.activityID)
    end
    if draft.mapID then
        local optionMapID = option.challengeMapID or option.mapID
        if optionMapID then
            return tonumber(draft.mapID) == tonumber(optionMapID)
        end
    end
    return false
end

local function ConfigureMeetingStoneModernDropdown(dropdown, visualWidth)
    dropdown:SetWidth(visualWidth or 170)
    if dropdown.SetHeight then
        dropdown:SetHeight(24)
    end
end

local function RefreshMeetingStoneModernDropdown(dropdown)
    if dropdown and dropdown.GenerateMenu then
        dropdown:GenerateMenu()
    end
end

local function CreateMeetingStoneDungeonDropdown(parent, owner, visualWidth)
    local dropdown = CreateFrame("DropdownButton", "MKMeetingStoneDungeonDropdown", parent, "WowStyle1DropdownTemplate")
    ConfigureMeetingStoneModernDropdown(dropdown, visualWidth)
    dropdown:SetSelectionText(function()
        return GetMeetingStoneDungeonDropdownText(owner)
    end)

    dropdown:SetupMenu(function(_, rootDescription)
        rootDescription:SetTag("MENU_MK_MEETINGSTONE_DUNGEON")
        local options = owner and owner.GetMeetingStoneDungeonOptions and owner:GetMeetingStoneDungeonOptions() or {}
        for _, option in ipairs(options) do
            rootDescription:CreateRadio(GetMeetingStoneDungeonOptionText(option), function(data)
                return owner and IsMeetingStoneDungeonOptionSelected(owner.meetingStoneDraft, data)
            end, function(data)
                if owner and owner.SelectMeetingStoneDungeonOption then
                    owner:SelectMeetingStoneDungeonOption(data)
                end
                RefreshMeetingStoneModernDropdown(dropdown)
                if owner and owner.RefreshMainWindow then
                    owner:RefreshMainWindow("MeetingStoneDungeonDropdown")
                end
            end, option)
        end
    end)

    return dropdown
end

local function GetMeetingStonePlayStyleDropdownText(owner)
    local draft = owner and owner.meetingStoneDraft
    local playStyle = draft and draft.playStyle or GetMeetingStoneDefaultPlayStyle()
    return GetMeetingStonePlayStyleText(playStyle)
end

local function CreateMeetingStonePlayStyleDropdown(parent, owner, visualWidth)
    local dropdown = CreateFrame("DropdownButton", "MKMeetingStonePlayStyleDropdown", parent, "WowStyle1DropdownTemplate")
    ConfigureMeetingStoneModernDropdown(dropdown, visualWidth)
    dropdown:SetSelectionText(function()
        return GetMeetingStonePlayStyleDropdownText(owner)
    end)

    dropdown:SetupMenu(function(_, rootDescription)
        rootDescription:SetTag("MENU_MK_MEETINGSTONE_PLAY_STYLE")
        local draft = owner and owner.meetingStoneDraft
        local selectedValue = draft and draft.playStyle or GetMeetingStoneDefaultPlayStyle()
        for _, option in ipairs(MEETINGSTONE_PLAY_STYLE_OPTIONS) do
            local value = GetMeetingStonePlayStyleValue(option)
            rootDescription:CreateRadio(TRANSLATE(option.textKey), function(data)
                return IsMeetingStonePlayStyleValueEqual(data.value, selectedValue)
            end, function(data)
                if owner and owner.SelectMeetingStonePlayStyleOption then
                    owner:SelectMeetingStonePlayStyleOption(data.option)
                end
                RefreshMeetingStoneModernDropdown(dropdown)
            end, {
                option = option,
                value = value,
            })
        end
    end)

    return dropdown
end


MeetingStoneForm.TrySetAtlas = TrySetMeetingStoneAtlas
MeetingStoneForm.CreateLabel = CreateMeetingStoneLabel
MeetingStoneForm.AddInputBackground = AddMeetingStoneInputBackground
MeetingStoneForm.AddTitleHolderBorder = AddMeetingStoneTitleHolderBorder
MeetingStoneForm.HideInputBoxChrome = HideMeetingStoneInputBoxChrome
MeetingStoneForm.StyleInputBox = StyleMeetingStoneInputBox
MeetingStoneForm.CreateInput = CreateMeetingStoneInput
MeetingStoneForm.SetInputPlaceholder = SetMeetingStoneInputPlaceholder
MeetingStoneForm.EnableSelectAllAfterMouseLeave = EnableMeetingStoneSelectAllAfterMouseLeave
MeetingStoneForm.CreateSummaryBox = CreateMeetingStoneSummaryBox
MeetingStoneForm.ApplySystemButtonStyle = ApplyMeetingStoneSystemButtonStyle
MeetingStoneForm.SetSystemButtonTextOffset = SetMeetingStoneSystemButtonTextOffset
MeetingStoneForm.CreateSystemButton = CreateMeetingStoneSystemButton
MeetingStoneForm.RefreshDropdown = RefreshMeetingStoneModernDropdown
MeetingStoneForm.CreateDungeonDropdown = CreateMeetingStoneDungeonDropdown
MeetingStoneForm.CreatePlayStyleDropdown = CreateMeetingStonePlayStyleDropdown
