require "ISUI/ISPanel"
require "ISUI/ISButton"
require "MS/MS_MatrixManager"
require "MS/SettingPanel/MS_PanelCollapseHelper"
require "MS/SettingPanel/MS_TitlePanelButtons"


MS_IndicatorSettingsPanel = ISPanel:derive("MS_IndicatorSettingsPanel")

local FONT_HGT_SMALL = getTextManager():getFontHeight(UIFont.Small)

local SETTING_PANEL_WIDTH_KEYS = {
    "IGUI_ModernStatus_Style",
    "IGUI_ModernStatus_Hide",
    "IGUI_ModernStatus_Unhide",
    "IGUI_ModernStatus_Lock",
    "IGUI_ModernStatus_Unlock",
    "IGUI_ModernStatus_KeepLayoutOnRelease",
    "IGUI_ModernStatus_AddToMatrix",
    "IGUI_ModernStatus_ReleaseFromMatrix",
    "IGUI_ModernStatus_AlwaysShowValue",
    "IGUI_ModernStatus_MonoIcon",
    "IGUI_ModernStatus_AutoHide",
    "IGUI_ModernStatus_Columns",
    "IGUI_ModernStatus_Rows",
    "IGUI_ModernStatus_SortDirection",
    "IGUI_ModernStatus_RowWidth",
    "IGUI_ModernStatus_RowHeight",
    "IGUI_ModernStatus_Opacity",
    "IGUI_ModernStatus_UseGradient",
    "IGUI_ModernStatus_ShowIcon",
    "IGUI_ModernStatus_IconPosition",
    "IGUI_ModernStatus_IconOpacity",
    "IGUI_ModernStatus_TextSize",
    "IGUI_ModernStatus_ShowName",
    "IGUI_ModernStatus_DisplayThresholds",
    "IGUI_ModernStatus_InvertDirection",
    "IGUI_ModernStatus_EnableAlarm",
    "IGUI_ModernStatus_AnimThreshold",
    "IGUI_ModernStatus_AutoHideThreshold",
    "IGUI_ModernStatus_SettingPanelWideProbe",
}

local function calculateWidestSettingPanelLabelWidth(textManager)
    local widestWidth = 0

    for _, key in ipairs(SETTING_PANEL_WIDTH_KEYS) do
        -- Compare localized labels at runtime because the widest option can differ by language.
        local candidateText = getText(key) .. " AAA"
        local candidateWidth = textManager:MeasureStringX(UIFont.Small, candidateText)
        if candidateWidth > widestWidth then
            widestWidth = candidateWidth
        end
    end

    return widestWidth
end


MS_IndicatorSettingsPanel.IndicatorNames = {
    ["ISThirstStatusIndicator"] = "IGUI_ModernStatus_Thirst",
    ["ISHungerStatusIndicator"] = "IGUI_ModernStatus_Hunger",
    ["ISEnduranceStatusIndicator"] = "IGUI_ModernStatus_Endurance",
    ["ISFatigueStatusIndicator"] = "IGUI_ModernStatus_Fatigue",
    ["ISStressStatusIndicator"] = "IGUI_ModernStatus_Stress",
    ["ISPanicStatusIndicator"] = "IGUI_ModernStatus_Panic",
    ["ISTemperatureStatusIndicator"] = "IGUI_ModernStatus_Temperature",
    ["ISWindchillStatusIndicator"] = "IGUI_ModernStatus_Windchill",
    ["ISHealthStatusIndicator"] = "IGUI_ModernStatus_Health",
    ["ISBoredomStatusIndicator"] = "IGUI_ModernStatus_Boredom",
    ["ISUnhappynessStatusIndicator"] = "IGUI_ModernStatus_Unhappyness",
    ["ISDiscomfortStatusIndicator"] = "IGUI_ModernStatus_Discomfort",
    ["ISSicknessStatusIndicator"] = "IGUI_ModernStatus_Sickness",
    ["ISCatchAColdStatusIndicator"] = "IGUI_ModernStatus_CatchACold",
    ["ISFoodHealingStatusIndicator"] = "IGUI_ModernStatus_FoodHealing",
    ["ISPoisonStatusIndicator"] = "IGUI_ModernStatus_Poison",
    ["ISPainStatusIndicator"] = "IGUI_ModernStatus_Pain",
    ["ISBleedingStatusIndicator"] = "IGUI_ModernStatus_Bleeding",
    ["ISCarryWeightStatusIndicator"] = "IGUI_invpanel_weight",
    ["ISCalorieStatusIndicator"] = "IGUI_ModernStatus_Calorie",
    ["ISProteinsStatusIndicator"] = "IGUI_ModernStatus_Proteins",
    ["ISCarbohydratesStatusIndicator"] = "IGUI_ModernStatus_Carbohydrates",
    ["ISLipidsStatusIndicator"] = "IGUI_ModernStatus_Lipids",
    ["ISWeightStatusIndicator"] = "IGUI_ModernStatus_Weight",
    ["ISMedicineStatusIndicator"] = "IGUI_ModernStatus_Medicine",
    ["ISAngerStatusIndicator"] = "IGUI_ModernStatus_Anger",
    ["ISDirtinessStatusIndicator"] = "IGUI_ModernStatus_Dirtiness",
    ["ISBloodinessStatusIndicator"] = "IGUI_ModernStatus_Bloodiness",
    ["ISWetnessStatusIndicator"] = "IGUI_ModernStatus_Wetness",
    ["ISDrunkennessStatusIndicator"] = "IGUI_ModernStatus_Drunkenness",
    ["ISStiffnessStatusIndicator"] = "IGUI_ModernStatus_Stiffness",
    ["ISNoxiousExposureStatusIndicator"] = "IGUI_ModernStatus_NoxiousExposure",
    ["ISNCBladderStatusIndicator"] = "IGUI_ModernStatus_NCBladder",
    ["ISNCBowelStatusIndicator"] = "IGUI_ModernStatus_NCBowel",
    ["ISNCGutHealthStatusIndicator"] = "IGUI_ModernStatus_NCGutHealth",
    ["ISNCSoilageStatusIndicator"] = "IGUI_ModernStatus_NCSoilage",
    ["ISNCDigestiveEffectsStatusIndicator"] = "IGUI_ModernStatus_NCDigestiveEffects",

}

MS_IndicatorSettingsPanel.CurrentPanel = nil

function MS_IndicatorSettingsPanel.calculateRequiredSize()
    local textManager = getTextManager()
    local baseWidth = calculateWidestSettingPanelLabelWidth(textManager) * 2
    
    local minWidth = 300
    local maxWidth = 500
    local panelW = math.max(minWidth, math.min(baseWidth, maxWidth))

    local rowheight = math.floor(FONT_HGT_SMALL*1.5)
    local numBarStyleItems = 23

    local titleBarHeight = math.floor(FONT_HGT_SMALL*1.2)
    local buttonHeight = math.floor(FONT_HGT_SMALL*1.5)
    local padding = math.floor(FONT_HGT_SMALL*0.2)
    local bottomButtonRows = 3

    local contentHeight = numBarStyleItems * rowheight

    local panelH = titleBarHeight + padding + buttonHeight + padding + contentHeight + padding + buttonHeight * bottomButtonRows + padding * bottomButtonRows
    
    local minHeight = 380
    panelH = math.max(minHeight, panelH)
    
    return {width = panelW, height = panelH}
end

function MS_IndicatorSettingsPanel:close()
    if MS_IndicatorSettingsPanel.CurrentPanel == self then
        MS_IndicatorSettingsPanel.CurrentPanel = nil
    end
    self:setVisible(false)
    self:removeFromUIManager()
end

-- ---------------------------------------------------------------------------------------- --
-- initialise
-- ---------------------------------------------------------------------------------------- --
function MS_IndicatorSettingsPanel:initialise()
    ISPanel.initialise(self)
end

function MS_IndicatorSettingsPanel:new(x, y, width, height, indicator)
    if not width or not height then
        local size = MS_IndicatorSettingsPanel.calculateRequiredSize()
        width = size.width
        height = size.height
    end
    local screenHeight = getCore():getScreenHeight()
    local maxHeight = math.max(320, screenHeight - 40)
    height = math.min(height, maxHeight)
    local o = ISPanel:new(x, y, width, height)
    setmetatable(o, self)
    self.__index = self
    
    o.indicator = indicator
    o.padding = math.floor(FONT_HGT_SMALL*0.2)
    o.moveWithMouse = false
    o.activeTab = self.TAB_CIRCULAR
    o.titleBarHeight = math.floor(FONT_HGT_SMALL*1.2)
    o.buttonHeight = math.floor(FONT_HGT_SMALL*1.5)
    o.moving = false

    o.TAB_CIRCULAR = 1
    o.TAB_Bar = 2

    o.titlebarbkg = NinePatchTexture.getSharedTexture("media/ui/ModernStatus/SettingPanel/TitleBarBG.png")
    o.contentbkg = NinePatchTexture.getSharedTexture("media/ui/ModernStatus/SettingPanel/ContentBackground.png")
    
    return o
end

-- ---------------------------------------------------------------------------------------- --
-- createChildren
-- ---------------------------------------------------------------------------------------- --
function MS_IndicatorSettingsPanel:createChildren()
    self:createTitleBar()
    
    local y = self.titleBarHeight + self.padding
    
    self:createStyleControl(y)
    
    self:createBottomButtons()
    
    if self.indicator then
        if self.indicator.isBarStyle then
            self:switchToTab(self.TAB_Bar)
        else
            self:switchToTab(self.TAB_CIRCULAR)
        end
    else
        self:switchToTab(self.TAB_CIRCULAR)
    end
end

function MS_IndicatorSettingsPanel:createTitleBar()
    local titleButtonSize = FONT_HGT_SMALL
    MS_PanelCollapseHelper.addTitleBarButton(self, titleButtonSize, self.indicator and self.indicator.isBarStyle and "BarStylePanel" or "CircularStylePanel")

    -- titleLabel
    self.titleLabel = ISLabel:new(MS_PanelCollapseHelper.getTitleLabelX(self, titleButtonSize), (self.titleBarHeight - FONT_HGT_SMALL) / 2, self.titleBarHeight, "", 1, 1, 1, 1, UIFont.Small, true)
    self.titleLabel:initialise()
    self.titleLabel.render = function()
        local indicatorType = self.indicator:getType()
        local titleKey = MS_IndicatorSettingsPanel.IndicatorNames[indicatorType]
        local fallbackTitle = titleKey and getText(titleKey) or indicatorType
        self.titleLabel:setName(MS_MatrixManager.getIndicatorDisplayTitle(indicatorType, fallbackTitle))
    end
    self:addChild(self.titleLabel)
    
    -- closeButton
    local closeSize = FONT_HGT_SMALL
    self.closeButton = MS_SquareButton:new(self:getWidth() - closeSize - self.padding, (self.titleBarHeight - FONT_HGT_SMALL) / 2, closeSize, getTexture("media/ui/ModernStatus/SettingPanel/Icon_Close.png"), self, MS_IndicatorSettingsPanel.close)
    self.closeButton:initialise()
    self.closeButton:setActive(true)
    self.closeButton:setActiveColor(0.8, 0.2, 0.2)
    self:addChild(self.closeButton)

    MS_TitlePanelButtons.addButtons(self, { "all", "matrix", "unlinked" }, closeSize)
end

function MS_IndicatorSettingsPanel:getIndicatorDisplayMode()
    if not self.indicator then
        return "circular"
    end

    if not self.indicator.isBarStyle then
        return "circular"
    end

    return self.indicator.isVertical and "vertical" or "horizontal"
end

function MS_IndicatorSettingsPanel:setIndicatorBarOrientation(wantVertical)
    if not self.indicator then return end

    local currentVertical = self.indicator.isVertical == true
    if currentVertical ~= wantVertical then
        local oldWidth = self.indicator:getWidth()
        local oldHeight = self.indicator:getHeight()
        self.indicator:setWidth(oldHeight)
        self.indicator:setHeight(oldWidth)
    end

    self.indicator.isVertical = wantVertical

    MSConfig.updateIndicatorConfig(self.indicator.playerIndex, self.indicator:getType(), "isVertical", wantVertical)
    MSConfig.updateIndicatorConfig(self.indicator.playerIndex, self.indicator:getType(), "barSize", { width = self.indicator:getWidth(), height = self.indicator:getHeight() })
end

function MS_IndicatorSettingsPanel:applyIndicatorDisplayMode(mode)
    if not self.indicator then return end

    if mode == "circular" then
        self.indicator:switchStyle(false)
        self:switchToTab(self.TAB_CIRCULAR)
        return
    end

    self.indicator:switchStyle(true)
    self:setIndicatorBarOrientation(mode == "vertical")
    self:switchToTab(self.TAB_Bar)
end

function MS_IndicatorSettingsPanel:getNextStyleMode()
    local currentMode = self:getIndicatorDisplayMode()
    if currentMode == "circular" then
        return "horizontal"
    end
    if currentMode == "horizontal" then
        return "vertical"
    end
    return "circular"
end

function MS_IndicatorSettingsPanel:createStyleControl(y)
    local middleX = math.floor(self:getWidth() / 2)
    local controlX = middleX + self.padding

    local styleLabel = ISLabel:new(self.padding, y + ((self.buttonHeight - FONT_HGT_SMALL) / 2), 0, getText("IGUI_ModernStatus_Style"), 1, 1, 1, 1, UIFont.Small, true)
    styleLabel:initialise()
    self:addChild(styleLabel)

    self.styleModeButton = MS_SquareButton:new(controlX, y + ((self.buttonHeight - self.buttonHeight) / 2), self.buttonHeight, MS_MatrixManager.getModeIconTexture(self:getIndicatorDisplayMode()), self, MS_IndicatorSettingsPanel.onStyleModeClick)
    self.styleModeButton:initialise()
    self.styleModeButton:setIconSizeRatio(0.7)
    self.styleModeButton.prerender = function(button)
        local mode = self:getIndicatorDisplayMode()
        button:setIcon(MS_MatrixManager.getModeIconTexture(mode))
        button:setActive(mode ~= "circular")
        if button.setTooltip then
            button:setTooltip(getText("IGUI_ModernStatus_Style"))
        end
    end
    self:addChild(self.styleModeButton)
end

function MS_IndicatorSettingsPanel:createBottomButtons()
    if not self.indicator then return end

    local buttonWidth = math.floor((self:getWidth() - self.padding * 3) / 2)
    local fullWidth = self:getWidth() - self.padding * 2
    local bottomY = self:getHeight() - self.buttonHeight - self.padding
    local linkY = bottomY - self.buttonHeight - self.padding
    local keepLayoutY = linkY - self.buttonHeight - self.padding

    -- Keep Layout on Release shares the same matrix option used by MatrixStylePanel.
    self.keepLayoutButton = MS_LongButton:new(self.padding, keepLayoutY, fullWidth, self.buttonHeight, getText("IGUI_ModernStatus_KeepLayoutOnRelease"), self, MS_IndicatorSettingsPanel.onToggleKeepLayoutOnRelease)
    self.keepLayoutButton:initialise()
    if self.keepLayoutButton.setTooltip then
        self.keepLayoutButton:setTooltip(getText("IGUI_ModernStatus_Tooltip_KeepLayoutOnRelease"))
    end
    self.keepLayoutButton.prerender = function()
        local config = MS_MatrixManager.getMatrixConfig(self.indicator.playerIndex)
        local enabled = config and config.keepLayoutOnRelease == true
        self.keepLayoutButton:setTitle(getText("IGUI_ModernStatus_KeepLayoutOnRelease"))
        self.keepLayoutButton:setActive(enabled)
        self.keepLayoutButton:setActiveColor(0.95, 0.5, 0.1)
        if self.keepLayoutButton.setTooltip then
            self.keepLayoutButton:setTooltip(getText("IGUI_ModernStatus_Tooltip_KeepLayoutOnRelease"))
        end
    end
    self:addChild(self.keepLayoutButton)

    -- Add/release the current indicator from the matrix without opening MatrixStylePanel.
    self.matrixLinkButton = MS_LongButton:new(self.padding, linkY, fullWidth, self.buttonHeight, getText("IGUI_ModernStatus_AddToMatrix"), self, MS_IndicatorSettingsPanel.onMatrixLinkButtonClick)
    self.matrixLinkButton:initialise()
    if self.matrixLinkButton.setTooltip then
        self.matrixLinkButton:setTooltip(getText("IGUI_ModernStatus_Tooltip_MatrixLinkToggle"))
    end
    self.matrixLinkButton.prerender = function()
        local linked = self.indicator and self.indicator.matrixLinked == true
        self.matrixLinkButton:setTitle(linked and getText("IGUI_ModernStatus_ReleaseFromMatrix") or getText("IGUI_ModernStatus_AddToMatrix"))
        self.matrixLinkButton:setActive(linked)
        self.matrixLinkButton:setActiveColor(0.95, 0.5, 0.1)
        if self.matrixLinkButton.setTooltip then
            self.matrixLinkButton:setTooltip(getText("IGUI_ModernStatus_Tooltip_MatrixLinkToggle"))
        end
    end
    self:addChild(self.matrixLinkButton)
    
    -- hide/show Button
    self.hideButton = MS_LongButton:new(self.padding, bottomY, buttonWidth, self.buttonHeight, getText("IGUI_ModernStatus_Hide"), self, MS_IndicatorSettingsPanel.onHideButtonClick)
    self.hideButton:initialise()
    self.hideButton.prerender = function()
        local isHidden = self.indicator and self.indicator.hidden == true
        self.hideButton:setTitle(isHidden and getText("IGUI_ModernStatus_Unhide") or getText("IGUI_ModernStatus_Hide"))
        self.hideButton:setActive(isHidden)
        self.hideButton:setActiveColor(0.95, 0.5, 0.1)
    end
    self:addChild(self.hideButton)
    
    -- lock/unlock Button
    self.lockButton = MS_LongButton:new(self:getWidth() - buttonWidth - self.padding, bottomY, buttonWidth, self.buttonHeight, getText("IGUI_ModernStatus_Lock"), self, MS_IndicatorSettingsPanel.onLockButtonClick)
    self.lockButton:initialise()
    self.lockButton.prerender = function()
        local isLocked = self.indicator and self.indicator.locked == true
        local text = isLocked and getText("IGUI_ModernStatus_Unlock") or getText("IGUI_ModernStatus_Lock")
        self.lockButton:setTitle(text)
        self.lockButton:setActive(isLocked)
        self.lockButton:setActiveColor(0.95, 0.5, 0.1)
    end
    self:addChild(self.lockButton)
end

-- ---------------------------------------------------------------------------------------- --
-- switch Tab
-- ---------------------------------------------------------------------------------------- --
function MS_IndicatorSettingsPanel:switchToTab(tabID)
    if not tabID then return end
    
    self.activeTab = tabID
    
    self:refreshTabContent(tabID)
end

function MS_IndicatorSettingsPanel:refreshTabContent(tabID)
    if self.contentPanel then
        self:removeChild(self.contentPanel)
        self.contentPanel:removeFromUIManager()
    end
    
    local y = self.titleBarHeight + self.padding + self.buttonHeight + self.padding
    local contentHeight = self:getHeight() - y - self.buttonHeight * 3 - self.padding * 4
    
    self.contentPanel = ISPanel:new(0, y, self:getWidth(), contentHeight)
    self.contentPanel.background = false
    self.contentPanel:initialise()
    self:addChild(self.contentPanel)
    
    if tabID == self.TAB_CIRCULAR then
        if self.indicator then
            local stylePanel = MS_CircularStylePanel:new(
                0, 0, 
                self.contentPanel:getWidth(), 
                self.contentPanel:getHeight(),
                self.indicator
            )
            stylePanel:initialise()
            stylePanel:instantiate()
            self.contentPanel:addChild(stylePanel)
            self.currentStylePanel = stylePanel
        end
    elseif tabID == self.TAB_Bar then
        if self.indicator then
            local stylePanel = MS_BarStylePanel:new(
                0, 0, 
                self.contentPanel:getWidth(), 
                self.contentPanel:getHeight(),
                self.indicator
            )
            stylePanel:initialise()
            stylePanel:instantiate()
            self.contentPanel:addChild(stylePanel)
            self.currentStylePanel = stylePanel
        end
    end
end

-- ---------------------------------------------------------------------------------------- --
-- Button Function
-- ---------------------------------------------------------------------------------------- --
function MS_IndicatorSettingsPanel:onStyleModeClick()
    if not self.indicator then return end

    -- Matrix-linked indicators inherit their live style and size from the matrix.
    -- Changing this per-indicator button while linked would overwrite the
    -- indicator's personal fallback layout with matrix-imposed values.
    if self.indicator.matrixLinked == true then
        return
    end

    self:applyIndicatorDisplayMode(self:getNextStyleMode())
end

function MS_IndicatorSettingsPanel:onToggleKeepLayoutOnRelease()
    if not self.indicator then return end

    local matrixConfig = MS_MatrixManager.getMatrixConfig(self.indicator.playerIndex)
    if not matrixConfig then return end

    MS_MatrixManager.updateMatrixConfig(self.indicator.playerIndex, "keepLayoutOnRelease", not (matrixConfig.keepLayoutOnRelease == true))
end

function MS_IndicatorSettingsPanel:onMatrixLinkButtonClick()
    if not self.indicator then return end

    MS_MatrixManager.setIndicatorLinked(self.indicator.playerIndex, self.indicator, not (self.indicator.matrixLinked == true))

    -- Linking/releasing can change the live layout/style, so refresh the visible controls.
    if self.activeTab then
        self:refreshTabContent(self.activeTab)
    end
end

function MS_IndicatorSettingsPanel:onHideButtonClick()
    if not self.indicator then return end
    
    self.indicator.hidden = not self.indicator.hidden
    
    self.indicator:setVisible(not self.indicator.hidden)
    
    MSConfig.updateIndicatorConfig(
        self.indicator.playerIndex,
        self.indicator:getType(),
        "hidden",
        self.indicator.hidden
    )

    if self.indicator.matrixLinked == true and MS_MatrixManager and MS_MatrixManager.applyMatrixLayout then
        MS_MatrixManager.applyMatrixLayout(self.indicator.playerIndex)
    end
end

function MS_IndicatorSettingsPanel:onLockButtonClick()
    if not self.indicator then return end
    
    self.indicator.locked = not self.indicator.locked
    
    self.indicator.moveWithMouse = not self.indicator.locked
    
    MSConfig.updateIndicatorConfig(
        self.indicator.playerIndex,
        self.indicator:getType(),
        "locked",
        self.indicator.locked
    )
end

-- ---------------------------------------------------------------------------------------- --
-- Mouse Function
-- ---------------------------------------------------------------------------------------- --
function MS_IndicatorSettingsPanel:onMouseDown(x, y)
    if y <= self.titleBarHeight then
        self.moving = true
        self:setCapture(true)
        return true
    end
    return ISPanel.onMouseDown(self, x, y)
end

function MS_IndicatorSettingsPanel:onMouseUp(x, y)
    if self.moving then
        self.moving = false
        self:setCapture(false)
    end
    return ISPanel.onMouseUp(self, x, y)
end

function MS_IndicatorSettingsPanel:onMouseMove(dx, dy)
    if self.moving then
        self:setX(self.x + dx)
        self:setY(self.y + dy)
    end
    return ISPanel.onMouseMove(self, dx, dy)
end

function MS_IndicatorSettingsPanel:onMouseMoveOutside(dx, dy)
    if self.moving then
        self:setX(self.x + dx)
        self:setY(self.y + dy)
    end
    return ISPanel.onMouseMoveOutside(self, dx, dy)
end

function MS_IndicatorSettingsPanel:onMouseUpOutside(x, y)
    self.moving = false
    self:setCapture(false)
    if MS_PanelCollapseHelper.onMouseUpOutside(self) then
        return true
    end
    return ISPanel.onMouseUpOutside(self, x, y)
end

-- ---------------------------------------------------------------------------------------- --
-- render
-- ---------------------------------------------------------------------------------------- --
function MS_IndicatorSettingsPanel:prerender()
    MS_PanelCollapseHelper.updateCollapsedPreviewFromMouse(self)

    local titlebarbkg = NinePatchTexture.getSharedTexture("media/ui/ModernStatus/SettingPanel/TitleBarBG.png")
    titlebarbkg:render(self:getAbsoluteX(), self:getAbsoluteY(), self:getWidth(), self.titleBarHeight, 0.5, 0.5, 0.5, 0.95)

    if MS_PanelCollapseHelper.isContentHidden(self) then
        return
    end

    local contentbkg = NinePatchTexture.getSharedTexture("media/ui/ModernStatus/SettingPanel/ContentBackground.png")
    contentbkg:render(self:getAbsoluteX(), self:getAbsoluteY() + self.titleBarHeight, self:getWidth(), self:getHeight() - self.titleBarHeight, 0.1, 0.1, 0.1, 0.8)
end