--[[
    Commander 3.0 - Buffer Line

    A single line in the virtual buffer.
    Lines are objects, not strings - they can be text, components,
    or live-updating elements.
]]

local ADDON_NAME, C3 = ...

-------------------------------------------------------------------------------
-- Line Class
-------------------------------------------------------------------------------

local Line = C3.class()
C3.BufferLine = Line

-- Line types
Line.TYPE = {
    TEXT = "text",          -- Simple text
    INPUT = "input",        -- User input (command)
    OUTPUT = "output",      -- Command output
    ERROR = "error",        -- Error message
    COMPONENT = "component", -- Rich component (grid, card, etc.)
    LIVE = "live",          -- Live-updating component
    SEPARATOR = "separator", -- Visual separator
    PROMPT = "prompt",      -- Prompt line
}

---Create a new line
---@param lineType string
---@param content any
---@param options? table
function Line:init(lineType, content, options)
    options = options or {}

    self.id = self:_generateId()
    self.type = lineType or Line.TYPE.TEXT
    self.content = content
    self.created = GetTime()
    self.modified = GetTime()

    -- Rendering
    self.visible = true
    self.height = options.height or 1  -- Lines can span multiple visual rows
    self.indent = options.indent or 0
    self.color = options.color
    self.font = options.font

    -- Metadata
    self.meta = options.meta or {}
    self.tags = options.tags or {}

    -- For live lines
    self.updateFn = options.updateFn
    self.interval = options.interval
    self._timer = nil

    -- For component lines
    self.component = options.component
    self.componentData = options.componentData
end

---Generate unique line ID
---@return string
function Line:_generateId()
    return string.format("line_%x%x", GetTime() * 1000, math.random(0xFFFF))
end

-------------------------------------------------------------------------------
-- Content Management
-------------------------------------------------------------------------------

---Get display text for this line
---@return string
function Line:GetText()
    if type(self.content) == "string" then
        return self.content
    elseif type(self.content) == "table" then
        if self.content._type then
            -- Typed object, use its formatter
            return C3.Types:Format(self.content)
        elseif self.content.display then
            return self.content.display
        elseif self.content.text then
            return self.content.text
        end
    end
    return tostring(self.content or "")
end

---Set line content
---@param content any
function Line:SetContent(content)
    self.content = content
    self.modified = GetTime()
end

---Append to line content (for text lines)
---@param text string
function Line:Append(text)
    if type(self.content) == "string" then
        self.content = self.content .. text
        self.modified = GetTime()
    end
end

-------------------------------------------------------------------------------
-- Visibility
-------------------------------------------------------------------------------

---Show this line
function Line:Show()
    self.visible = true
end

---Hide this line
function Line:Hide()
    self.visible = false
end

---Toggle visibility
function Line:Toggle()
    self.visible = not self.visible
end

---Check if visible
---@return boolean
function Line:IsVisible()
    return self.visible
end

-------------------------------------------------------------------------------
-- Styling
-------------------------------------------------------------------------------

---Set line color
---@param r number|string Red (0-1) or hex color
---@param g? number Green (0-1)
---@param b? number Blue (0-1)
function Line:SetColor(r, g, b)
    if type(r) == "string" then
        self.color = r  -- Hex or named color
    else
        self.color = { r = r, g = g, b = b }
    end
    self.modified = GetTime()
end

---Set indent level
---@param level number
function Line:SetIndent(level)
    self.indent = level
    self.modified = GetTime()
end

-------------------------------------------------------------------------------
-- Tags & Metadata
-------------------------------------------------------------------------------

---Add a tag
---@param tag string
function Line:AddTag(tag)
    self.tags[tag] = true
end

---Remove a tag
---@param tag string
function Line:RemoveTag(tag)
    self.tags[tag] = nil
end

---Check if line has tag
---@param tag string
---@return boolean
function Line:HasTag(tag)
    return self.tags[tag] == true
end

---Set metadata
---@param key string
---@param value any
function Line:SetMeta(key, value)
    self.meta[key] = value
end

---Get metadata
---@param key string
---@return any
function Line:GetMeta(key)
    return self.meta[key]
end

-------------------------------------------------------------------------------
-- Live Updates
-------------------------------------------------------------------------------

---Start live updates
---@param updateFn function
---@param interval? number Seconds between updates
function Line:StartLive(updateFn, interval)
    self.type = Line.TYPE.LIVE
    self.updateFn = updateFn
    self.interval = interval or 1

    -- Create timer
    if C_Timer and C_Timer.NewTicker then
        self._timer = C_Timer.NewTicker(self.interval, function()
            self:Update()
        end)
    end
end

---Stop live updates
function Line:StopLive()
    if self._timer then
        self._timer:Cancel()
        self._timer = nil
    end
    self.updateFn = nil
end

---Trigger update
function Line:Update()
    if self.updateFn then
        local newContent = self.updateFn(self)
        if newContent ~= nil then
            self:SetContent(newContent)
        end
    end
end

---Check if line is live
---@return boolean
function Line:IsLive()
    return self.type == Line.TYPE.LIVE and self.updateFn ~= nil
end

-------------------------------------------------------------------------------
-- Factory Methods
-------------------------------------------------------------------------------

---Create a text line
---@param text string
---@param options? table
---@return Line
function Line.Text(text, options)
    return Line:new(Line.TYPE.TEXT, text, options)
end

---Create an input line (user command)
---@param command string
---@param options? table
---@return Line
function Line.Input(command, options)
    options = options or {}
    -- Use theme color (nord13 yellow/gold) for user commands
    local inputColor = C3.UI and C3.UI.Theme and C3.UI.Theme:GetColor("status.gold") or "EBCB8B"
    options.color = options.color or inputColor
    return Line:new(Line.TYPE.INPUT, command, options)
end

---Create an output line
---@param content any
---@param options? table
---@return Line
function Line.Output(content, options)
    return Line:new(Line.TYPE.OUTPUT, content, options)
end

---Create an error line
---@param message string
---@param options? table
---@return Line
function Line.Error(message, options)
    options = options or {}
    -- Use theme color (nord11 red) for errors
    local errorColor = C3.UI and C3.UI.Theme and C3.UI.Theme:GetColor("accent.error") or "BF616A"
    options.color = options.color or errorColor
    return Line:new(Line.TYPE.ERROR, message, options)
end

---Create a separator line
---@param char? string
---@param options? table
---@return Line
function Line.Separator(char, options)
    options = options or {}
    char = char or "-"
    local sep = string.rep(char, 60)
    return Line:new(Line.TYPE.SEPARATOR, sep, options)
end

---Create a prompt line
---@param prompt string
---@param options? table
---@return Line
function Line.Prompt(prompt, options)
    options = options or {}
    -- Use theme color (nord14 green) for prompts
    local promptColor = C3.UI and C3.UI.Theme and C3.UI.Theme:GetColor("accent.success") or "A3BE8C"
    options.color = options.color or promptColor
    return Line:new(Line.TYPE.PROMPT, prompt, options)
end

---Create a component line
---@param component table
---@param data? table
---@param options? table
---@return Line
function Line.Component(component, data, options)
    options = options or {}
    options.component = component
    options.componentData = data
    return Line:new(Line.TYPE.COMPONENT, nil, options)
end

---Create a live line
---@param updateFn function
---@param interval? number
---@param options? table
---@return Line
function Line.Live(updateFn, interval, options)
    options = options or {}
    options.updateFn = updateFn
    options.interval = interval or 1
    local line = Line:new(Line.TYPE.LIVE, nil, options)
    line:Update() -- Initial update

    -- Start the timer for periodic updates
    if C_Timer and C_Timer.NewTicker then
        line._timer = C_Timer.NewTicker(line.interval, function()
            line:Update()
        end)
    end

    return line
end

return Line
