-- NAME: 2048
-- DESC: Merge tiles to reach 2048

-- Game states
local STATE_MENU = 0
local STATE_PLAYING = 1
local STATE_GAME_OVER = 2
local STATE_WIN = 3

-- Game constants
local GRID_SIZE = 4
local TILE_SIZE = 20
local TILE_SPACING = 2

function init()
    game.vars.state = STATE_MENU
    game.vars.score = 0
    
    -- Grid (4x4, 0 = empty)
    game.vars.grid = {}
    for y = 1, GRID_SIZE do
        game.vars.grid[y] = {}
        for x = 1, GRID_SIZE do
            game.vars.grid[y][x] = 0
        end
    end
    
    game.vars.moved = false
    game.vars.won = false
    
    -- Enable continuous updates
    game.set_frame_updates(true)
    
    print("2048 initialized")
end

function update(event)
    local state = game.vars.state
    
    if state == STATE_MENU then
        if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
            reset_game()
            game.vars.state = STATE_PLAYING
            return true
        end
    
    elseif state == STATE_PLAYING then
        if event.type == INPUT.TOUCH_DOWN then
            -- Determine swipe direction
            local direction = get_swipe_direction(event.x, event.y)
            if direction then
                game.vars.moved = false
                move_tiles(direction)
                
                if game.vars.moved then
                    spawn_tile()
                    
                    -- Check win/lose
                    if has_tile(2048) then
                        if not game.vars.won then
                            game.vars.state = STATE_WIN
                            game.vars.won = true
                        end
                    end
                    
                    if not can_move() then
                        game.vars.state = STATE_GAME_OVER
                    end
                    
                    return true
                end
            end
        end
    
    elseif state == STATE_WIN then
        if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
            -- Can continue playing or go to menu
            if event.y < game.height() / 2 then
                game.vars.state = STATE_PLAYING
            else
                game.vars.state = STATE_MENU
            end
            return true
        end
    
    elseif state == STATE_GAME_OVER then
        if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
            game.vars.state = STATE_MENU
            return true
        end
    end
    
    return false
end

function draw()
    renderer.clear(false)
    
    local state = game.vars.state
    
    if state == STATE_MENU then
        renderer.text(game.width() / 2 - 15, game.height() / 2 - 30, "2048", true)
        renderer.text(game.width() / 2 - 50, game.height() / 2, "Tap to Start", true)
    
    elseif state == STATE_PLAYING or state == STATE_WIN or state == STATE_GAME_OVER then
        -- Draw grid
        local start_x = (game.width() - (GRID_SIZE * (TILE_SIZE + TILE_SPACING))) / 2
        local start_y = 20
        
        for y = 1, GRID_SIZE do
            for x = 1, GRID_SIZE do
                local tile_x = start_x + (x - 1) * (TILE_SIZE + TILE_SPACING)
                local tile_y = start_y + (y - 1) * (TILE_SIZE + TILE_SPACING)
                local value = game.vars.grid[y][x]
                
                if value == 0 then
                    -- Empty tile
                    renderer.rect(tile_x, tile_y, TILE_SIZE, TILE_SIZE, true, false)
                else
                    -- Filled tile
                    renderer.rect(tile_x, tile_y, TILE_SIZE, TILE_SIZE, true, true)
                    
                    -- Draw value (simplified)
                    local text = tostring(value)
                    if string.len(text) <= 2 then
                        renderer.text(tile_x + 2, tile_y + 2, text, false)
                    else
                        renderer.text(tile_x + 1, tile_y + 2, text, false)
                    end
                end
            end
        end
        
        -- Draw score
        renderer.text(10, 10, "Score: " .. tostring(game.vars.score), true)
        
        if state == STATE_WIN then
            renderer.text(game.width() / 2 - 30, game.height() / 2 - 20, "YOU WIN!", true)
            renderer.text(game.width() / 2 - 60, game.height() / 2, "Tap up: Continue", true)
            renderer.text(game.width() / 2 - 50, game.height() / 2 + 15, "Tap down: Menu", true)
        end
        
        if state == STATE_GAME_OVER then
            renderer.text(game.width() / 2 - 40, game.height() / 2, "GAME OVER", true)
            renderer.text(game.width() / 2 - 30, game.height() / 2 + 15, "Score: " .. tostring(game.vars.score), true)
            renderer.text(game.width() / 2 - 60, game.height() / 2 + 30, "Tap to Menu", true)
        end
    end
end

function get_swipe_direction(x, y)
    -- Simple tap-based direction (could be enhanced with swipe tracking)
    local mid_x = game.width() / 2
    local mid_y = game.height() / 2
    
    local dx = x - mid_x
    local dy = y - mid_y
    
    if math.abs(dx) > math.abs(dy) then
        if dx > 0 then return "right" end
        return "left"
    else
        if dy > 0 then return "down" end
        return "up"
    end
end

function move_tiles(direction)
    local old_grid = {}
    for y = 1, GRID_SIZE do
        old_grid[y] = {}
        for x = 1, GRID_SIZE do
            old_grid[y][x] = game.vars.grid[y][x]
        end
    end
    
    if direction == "left" then
        move_left()
    elseif direction == "right" then
        move_right()
    elseif direction == "up" then
        move_up()
    elseif direction == "down" then
        move_down()
    end
    
    -- Check if grid changed
    for y = 1, GRID_SIZE do
        for x = 1, GRID_SIZE do
            if old_grid[y][x] ~= game.vars.grid[y][x] then
                game.vars.moved = true
                return
            end
        end
    end
end

function move_left()
    for y = 1, GRID_SIZE do
        -- Compact
        local row = {}
        for x = 1, GRID_SIZE do
            if game.vars.grid[y][x] ~= 0 then
                table.insert(row, game.vars.grid[y][x])
            end
        end
        
        -- Merge
        local i = 1
        while i < #row do
            if row[i] == row[i + 1] then
                row[i] = row[i] * 2
                game.vars.score = game.vars.score + row[i]
                table.remove(row, i + 1)
            end
            i = i + 1
        end
        
        -- Fill back
        for x = 1, GRID_SIZE do
            if x <= #row then
                game.vars.grid[y][x] = row[x]
            else
                game.vars.grid[y][x] = 0
            end
        end
    end
end

function move_right()
    for y = 1, GRID_SIZE do
        local row = {}
        for x = GRID_SIZE, 1, -1 do
            if game.vars.grid[y][x] ~= 0 then
                table.insert(row, game.vars.grid[y][x])
            end
        end
        
        local i = 1
        while i < #row do
            if row[i] == row[i + 1] then
                row[i] = row[i] * 2
                game.vars.score = game.vars.score + row[i]
                table.remove(row, i + 1)
            end
            i = i + 1
        end
        
        for x = GRID_SIZE, 1, -1 do
            if GRID_SIZE - x + 1 <= #row then
                game.vars.grid[y][x] = row[GRID_SIZE - x + 1]
            else
                game.vars.grid[y][x] = 0
            end
        end
    end
end

function move_up()
    for x = 1, GRID_SIZE do
        local col = {}
        for y = 1, GRID_SIZE do
            if game.vars.grid[y][x] ~= 0 then
                table.insert(col, game.vars.grid[y][x])
            end
        end
        
        local i = 1
        while i < #col do
            if col[i] == col[i + 1] then
                col[i] = col[i] * 2
                game.vars.score = game.vars.score + col[i]
                table.remove(col, i + 1)
            end
            i = i + 1
        end
        
        for y = 1, GRID_SIZE do
            if y <= #col then
                game.vars.grid[y][x] = col[y]
            else
                game.vars.grid[y][x] = 0
            end
        end
    end
end

function move_down()
    for x = 1, GRID_SIZE do
        local col = {}
        for y = GRID_SIZE, 1, -1 do
            if game.vars.grid[y][x] ~= 0 then
                table.insert(col, game.vars.grid[y][x])
            end
        end
        
        local i = 1
        while i < #col do
            if col[i] == col[i + 1] then
                col[i] = col[i] * 2
                game.vars.score = game.vars.score + col[i]
                table.remove(col, i + 1)
            end
            i = i + 1
        end
        
        for y = GRID_SIZE, 1, -1 do
            if GRID_SIZE - y + 1 <= #col then
                game.vars.grid[y][x] = col[GRID_SIZE - y + 1]
            else
                game.vars.grid[y][x] = 0
            end
        end
    end
end

function spawn_tile()
    local empty = {}
    for y = 1, GRID_SIZE do
        for x = 1, GRID_SIZE do
            if game.vars.grid[y][x] == 0 then
                table.insert(empty, {x = x, y = y})
            end
        end
    end
    
    if #empty > 0 then
        local pos = empty[math.random(1, #empty)]
        game.vars.grid[pos.y][pos.x] = math.random() > 0.9 and 4 or 2
    end
end

function has_tile(value)
    for y = 1, GRID_SIZE do
        for x = 1, GRID_SIZE do
            if game.vars.grid[y][x] == value then
                return true
            end
        end
    end
    return false
end

function can_move()
    -- Check if any empty tiles
    for y = 1, GRID_SIZE do
        for x = 1, GRID_SIZE do
            if game.vars.grid[y][x] == 0 then
                return true
            end
        end
    end
    
    -- Check if any merges possible
    for y = 1, GRID_SIZE do
        for x = 1, GRID_SIZE do
            local val = game.vars.grid[y][x]
            if x < GRID_SIZE and game.vars.grid[y][x + 1] == val then return true end
            if y < GRID_SIZE and game.vars.grid[y + 1][x] == val then return true end
        end
    end
    
    return false
end

function reset_game()
    game.vars.score = 0
    game.vars.won = false
    
    for y = 1, GRID_SIZE do
        for x = 1, GRID_SIZE do
            game.vars.grid[y][x] = 0
        end
    end
    
    spawn_tile()
    spawn_tile()
end
