--# LifeUI
-- Conway Sphere – ImmediateUI overlay (UI only; no sim hooks yet)

LifeUI = {
    -- runtime state
    state = {
        drawing     = false,
        playing     = true,
        showPreview = false,
        showSettings= false,
        toolbarOpen = false,
        settingsTab = 1,   -- 1=Rules, 2=Colors
        presetName  = "Conway (S23/B3)",
        showCubemap = true
    },
    animT = 0, -- 0=collapsed, 1=expanded
    safeTopPad = 44,
    -- user prefs (persisted)
    prefs = {
        -- rules: survival & birth sets (bool[0..8])
        S = { [0]=false,false,true, true, false,false,false,false,false }, -- S23
        B = { [0]=false,false,false, true, false,false,false,false,false }, -- B3
        colors = {
            alive = color(70, 200, 255),
            dead  = color(16, 20, 28, 220),
            grid  = color(255, 255, 255, 30),
            bg    = color(8, 10, 16),
            settingsStroke = color(55, 58, 194, 150),
            settingsFill   = color(255, 172)
        }
    },
    -- internal
    _changed = false,
    ui = { 
        numPadScale   = 0.93,        -- 0..1, shrink/expand keys uniformly
        numPadSpacing = 8,         -- gap (px). If nil we auto-size per box.
        panelMarginPercent = 0.05,
        defaultEmojiTint =         color(238, 236, 241, 224) ,
        decay = { xFrac = 0.50, wFrac = 0.90, trackPx = 8,  fontPx = 18 },
        seed  = { xFrac = 0.50, wFrac = 0.90, trackPx = 8,  fontPx = 18 }
    }
}


-- ──────────────────────────────────────────────────────────────
-- Persistence
local PREF_KEY = "LifeSphere:UIv1"

function LifeUI.loadPrefs()
    local ok, data = pcall(getLocalData, PREF_KEY, nil)
    if ok and data then
        local ok2, t = pcall(json.decode, data)
        if ok2 and type(t)=="table" then
            -- merge shallowly to tolerate new fields
            for k,v in pairs(t) do
                if k=="colors" and type(v)=="table" then
                    for ck,cv in pairs(v) do LifeUI.prefs.colors[ck] = color(cv.r,cv.g,cv.b,cv.a or 255) end
                elseif (k=="S" or k=="B") and type(v)=="table" then
                    for i=0,8 do LifeUI.prefs[k][i] = not not v[tostring(i)] or not not v[i] end
                elseif LifeUI.prefs[k] ~= nil then
                    LifeUI.prefs[k] = v
                    -- in LifeUI.loadPrefs()
                elseif k=="decayTurns" then
                    LifeUI.prefs.decayTurns = tonumber(v) or -1
                end
            end
        end
    end
    -- also restore last toolbar state if you saved it earlier
end

function LifeUI.attachModel(model)
    LifeUI.model = model
end

function LifeUI.savePrefs()
    -- store plain RGBA for colors, numeric-index sets as strings (robust with json)
    local out = { S={}, B={}, colors={} }
    for i=0,8 do out.S[tostring(i)] = LifeUI.prefs.S[i] and true or false end
    for i=0,8 do out.B[tostring(i)] = LifeUI.prefs.B[i] and true or false end
    for k,c in pairs(LifeUI.prefs.colors) do
        out.colors[k] = { r=c.r, g=c.g, b=c.b, a=c.a }
        end
    out.decayTurns = LifeUI.prefs.decayTurns
    saveLocalData(PREF_KEY, json.encode(out))
end

-- ──────────────────────────────────────────────────────────────
-- Presets (UI labels → S,B)
local RULE_PRESETS = {
    ["Conway (S23/B3)"]      = { S={2,3},     B={3} },
    ["HighLife (S23/B36)"]   = { S={2,3},     B={3,6} },
    ["Seeds (S-/B2)"]        = { S={},        B={2} },
    ["Life w/4 (S23/B34)"]   = { S={2,3},     B={3,4} },
    ["Replicator (S1357/B1357)"]= { S={1,3,5,7}, B={1,3,5,7} },
    ["Maze (S12345/B3)"]     = { S={1,2,3,4,5}, B={3} },
    ["Gnarl (S1/B1)"]        = { S={1},       B={1} }
}

function LifeUI.applyPreset(name)
    local p = RULE_PRESETS[name]
    if not p then return end
    for i=0,8 do LifeUI.prefs.S[i] = false; LifeUI.prefs.B[i] = false end
    for _,n in ipairs(p.S) do LifeUI.prefs.S[n] = true end
    for _,n in ipairs(p.B) do LifeUI.prefs.B[n] = true end
    LifeUI.state.presetName = name
    LifeUI._changed = true
end

function randomizeRules()
    for i=0,8 do
        LifeUI.prefs.S[i] = (math.random() < 0.33)
        LifeUI.prefs.B[i] = (math.random() < 0.33)
    end
    LifeUI.state.presetName = "Custom"
    LifeUI._changed = true
end

-- ──────────────────────────────────────────────────────────────
-- Small helpers
local function pill(x,y,w,h,label,active)
    pushStyle()
    if active then fill(255) stroke(50) else fill(70,120) stroke(200) end
    strokeWidth(2)
    button(label, x, y, w, h, nil, {radius=14, corners=15})
    popStyle()
end

local function swatch(x,y,w,h,c,label)
    pushStyle()
    fill(c) stroke(255,80) strokeWidth(2)
    roundedRectangle{ x=x, y=y, w=w, h=h, corners=15, radius=12 }
    fill(0,180) textMode(CENTER) textAlign(CENTER) fontSize(14)
    text(label, x, y - h*0.65)
    popStyle()
end

-- ──────────────────────────────────────────────────────────────
local icons = { "▶️","⏭️","🔄","✏️","▫️","⚙️","✔️" }
local menuWidget = "🔘"

-- Button drawing helper with optional tint and flash
-- Button drawing helper with press flash and optional overlay (e.g., ✖️)
function emojiButton(cx, y, glyph, key, onTap, targetH, aTint, overlayFn)
    pushStyle()
    -- hit zone sized to the glyph
    font("HelveticaNeue")
    fontSize(targetH * 0.8)
    local tw, th = textSize(glyph)
    local bw, bh = tw + 20, targetH
    
    -- invisible tap target (no border/background)
    fill(0, 0)
    stroke(191, 218, 225, 53)
    strokeWidth(0)
    button("", cx, y, bw, bh, onTap, { key = key, radius = 20 })
    
    -- draw the main emoji
    textAlign(CENTER)
    textMode(CENTER)
    if aTint then 
        fill(aTint) 
    else 
        fill(LifeUI.ui.defaultEmojiTint) 
        --fill(255)
    end
    text(glyph, cx, y)
    
    popStyle()
end

function LifeUI.drawToolbar()
    local topH = 52
    local y = HEIGHT - LifeUI.safeTopPad - topH/2 - 6
    local pad = 20
    local N = #icons
    local laneW = (WIDTH - pad*2)/N
    
    local a = LifeUI.animT
    
    -- collapsed menuWidget
    if a < 0.01 then
        emojiButton(WIDTH - pad - 20, y, menuWidget, "tb:menu", function()
            LifeUI.state.toolbarOpen = true
            tween(0.25, LifeUI, { animT = 1 }, tween.easing.cubicInOut)
        end, topH, color(90,204))
        return
    end
    
    -- expanded icons (animate out from menuWidget)
    local startX = WIDTH - pad - 20
    for i, glyph in ipairs(icons) do
        local targetX = pad + (i - 0.5) * laneW
        local cx = startX + (targetX - startX) * a
        
        -- dynamic glyph for play/pause (correct orientation)
        local g = glyph
        if i == 1 then
            g = LifeUI.state.playing and "⏸️" or "▶️"
        end
        
        -- callbacks
        local tapFn = function() end
        if i == 1 then
            -- toggle play/pause
            tapFn = function()
                LifeUI.state.playing = not LifeUI.state.playing
            end
        elseif i == 2 then
            -- step: do a step AND force pause
            tapFn = function()
                print("step")
                LifeUI.state.playing = false
            end
        elseif i == 3 then
            tapFn = function()
                if LifeUI.model then
                    LifeUI.model:clearAll()
                    lifeRenderer:fullRedraw()
                    LifeUI.model:seedRandomCells()
                    lifeRenderer:applyDirty()
                end
            end
        elseif i == 4 then
            tapFn = function() LifeUI.state.drawing = not LifeUI.state.drawing end
        elseif i == 5 then
            -- show/hide cubemap
            tapFn = function() ShowCubeMap = not ShowCubeMap end
        elseif i == 6 then
            tapFn = function() LifeUI.state.showSettings = not LifeUI.state.showSettings end
        elseif i == 7 then
            tapFn = function()
                LifeUI.state.toolbarOpen = false
                LifeUI.state.showSettings = false
                tween(0.25, LifeUI, { animT = 0 }, tween.easing.cubicInOut)
            end
        end
        
        -- tint rules (emoji-only; no bg state change)
        local tintCol = nil
        if i == 4 then
            -- pencil gray when disabled
            tintCol = LifeUI.state.drawing and color(255) or color(118,145,159,219)
        elseif i == 5 then
            -- cubemap: bright when shown, gray when hidden
            tintCol = ShowCubeMap and color(198, 210, 225) or color(118,145,159,219)
        end
        
        emojiButton(cx, y, g, "tb:"..i, tapFn, topH, tintCol, nil)
    end
end

-- ──────────────────────────────────────────────────────────────
-- Settings: Rules tab
local function drawRulesTab(w, h)
    local cx = w/2
    local y  = h - 60
    
    -- Presets scroller (simple 2-column grid of buttons)
    fontSize(18)
    local colW = (w - 60) / 2
    local rowH = 36
    local i = 0
    for name,_ in pairs(RULE_PRESETS) do
        local col = (i % 2)
        local row = math.floor(i / 2)
        local bx  = 30 + colW/2 + col*colW
        local by  = y - row*44
        local active = (LifeUI.state.presetName == name)
        pushStyle()
        if active then fill(255) stroke(50) else fill(60, 120) stroke(200) end
        button(name, bx, by, colW-16, rowH, function()
            LifeUI.applyPreset(name)
        end, {radius=12, corners=15})
        popStyle()
        i = i + 1
    end
    y = y - math.ceil(i/2)*44 - 10
    
    -- Manual configuration (S: survival, B: birth)
    fontSize(16)
    fill(255) textAlign(CENTER)
    text("Survive (S): tap counts to toggle", w*0.28, y)
    text("Birth (B): tap counts to toggle",    w*0.72, y)
    y = y - 28
    
    -- Nine small toggles 0..8 for S and B
    local function miniToggleGrid(baseX, label, set)
        local cell = 32
        local startX = baseX - (cell*9)/2 + cell/2
        for n=0,8 do
            local bx = startX + n*cell
            local on = set[n] and true or false
            pushStyle()
            if on then fill(255) stroke(50) else fill(50,120) stroke(200) end
            button(tostring(n), bx, y, 28, 28, function()
                set[n] = not set[n]; LifeUI.state.presetName = "Custom"
                LifeUI._changed = true
            end, {radius=8, corners=15})
            popStyle()
        end
    end
    miniToggleGrid(w*0.28, "S", LifeUI.prefs.S)
    miniToggleGrid(w*0.72, "B", LifeUI.prefs.B)
    
    y = y - 50
    
    -- Randomize + Note
    pushStyle()
    fill(200) stroke(255) strokeWidth(2)
    button("Randomize Rules", w/2, y, 220, 40, function() randomizeRules() end, {radius=14, corners=15})
    popStyle()
end

-- Settings: Colors tab
local function drawColorsTab(w, h)
    local cx = w/2
    local y  = h - 60
    fontSize(18)
    
    -- Four swatches with wheels under each
    local labels = {
        {"Alive", "alive"},
        {"Dead",  "dead"},
        {"Grid",  "grid"},
        {"BG",    "bg"}
    }
    local spacing = w/4
    for i,entry in ipairs(labels) do
        local title, key = entry[1], entry[2]
        local x = spacing*(i-0.5)
        local c = LifeUI.prefs.colors[key]
        swatch(x, y, 120, 40, c, title)
        -- color wheel
        colorWheel("cw_"..key, x, y-140, 70, function(newCol)
            LifeUI.prefs.colors[key] = newCol
            LifeUI._changed = true
        end)
    end
    
    -- Reset & Apply row
    pushStyle()
    y = 70
    fill(60, 120) stroke(200)
    button("Reset Defaults", cx - 140, y, 220, 40, function()
        LifeUI.prefs.colors.alive = color(70,200,255)
        LifeUI.prefs.colors.dead  = color(16,20,28,220)
        LifeUI.prefs.colors.grid  = color(255,255,255,30)
        LifeUI.prefs.colors.bg    = color(8,10,16)
        LifeUI._changed = true
    end, {radius=14, corners=15})
    
    fill(200) stroke(255)
    button("Save Colors", cx + 140, y, 220, 40, function()
        LifeUI.savePrefs()
        print("Colors saved")
    end, {radius=14, corners=15})
    popStyle()
end

-- Public: call these from your Main draw()
function LifeUI.draw()    
    LifeUI.drawToolbar()
    LifeUI.drawSettings()
end

-- Call this once in setup()
function LifeUI.init()
    if not json then print("⚠️ json module required for prefs") end
    LifeUI.loadPrefs()
end