-- pxl8 tile properties dialog menu
-- provides a ui for editing custom properties on tilemap tiles

local DEBUG = false

local function log(msg)
  if DEBUG then
    print("[tile-properties] " .. msg)
  end
end

local function get_selected_tile()
  log("get_selected_tile() called")

  if not app then
    log("ERROR: app is nil!")
    return nil
  end

  local sprite = app.sprite
  log("sprite: " .. tostring(sprite))
  if not sprite then
    log("No sprite selected")
    return nil
  end

  local layer = app.layer
  log("layer: " .. tostring(layer))
  if not layer or not layer.isTilemap then
    log("Layer is not a tilemap")
    return nil
  end

  local tileset = layer.tileset
  log("tileset: " .. tostring(tileset))
  if not tileset then
    log("No tileset in layer")
    return nil
  end

  local tileIndex = app.fgTile
  log("tileIndex: " .. tostring(tileIndex))
  if not tileIndex or tileIndex < 0 then
    log("Invalid tile index")
    return nil
  end

  log("Selected tile: tileset=" .. tostring(tileset) .. ", index=" .. tostring(tileIndex))
  return tileset, tileIndex
end

local function get_tile_properties(tileset, tile_index)
  log("get_tile_properties() called for tile index: " .. tostring(tile_index))

  local tile = tileset:tile(tile_index)
  if not tile then
    log("Could not get tile object")
    return {}
  end

  if not tile.properties then
    log("Tile has no properties")
    return {}
  end

  local props = {}
  for key, value in pairs(tile.properties) do
    local propType = "string"
    if type(value) == "boolean" then
      propType = "boolean"
    elseif type(value) == "number" then
      propType = "number"
    end

    table.insert(props, {
      key = key,
      type = propType,
      value = value
    })
  end

  log("Found " .. #props .. " properties")
  return props
end

local function set_tile_properties(tileset, tile_index, props)
  log("set_tile_properties() called for tile index: " .. tostring(tile_index))

  local tile = tileset:tile(tile_index)
  if not tile then
    log("Could not get tile object")
    return
  end

  tile.properties = {}
  local count = 0
  for _, prop in ipairs(props) do
    if prop.key and prop.key ~= "" then
      local value = prop.value
      if prop.type == "boolean" then
        value = (value == true or value == "true")
      elseif prop.type == "number" then
        value = tonumber(value) or 0
      end
      tile.properties[prop.key] = value
      count = count + 1
    end
  end
  log("Set " .. count .. " properties")
end

local function show_property_editor()
  log("show_property_editor() called")

  local tileset, tile_index = get_selected_tile()

  if not tileset then
    log("No tileset selected, showing alert")
    app.alert("Please select a tile in the tileset")
    return
  end

  log("Getting properties for tile")
  local properties = get_tile_properties(tileset, tile_index)

  local function build_dialog()
    local dlg = Dialog("Tile Properties - Tile #" .. tile_index)

    for i, prop in ipairs(properties) do
      local id_prefix = "prop_" .. i .. "_"
      local prop_value = prop

      dlg:separator{ id = id_prefix .. "sep" }
      dlg:newrow()

      dlg:entry{
        id = id_prefix .. "key",
        label = "Name:",
        text = prop_value.key
      }
      dlg:newrow()

      dlg:combobox{
        id = id_prefix .. "type",
        label = "Type:",
        option = prop_value.type,
        options = { "boolean", "number", "string" },
        onchange = function()
          local new_type = dlg.data[id_prefix .. "type"]
          if new_type ~= prop_value.type then
            if new_type == "boolean" then
              properties[i].value = false
            elseif new_type == "number" then
              properties[i].value = 0
            else
              properties[i].value = ""
            end
            properties[i].type = new_type
            rebuild_from_dialog(dlg)
          end
        end
      }
      dlg:newrow()

      if prop_value.type == "boolean" then
        dlg:check{
          id = id_prefix .. "value",
          label = "Value:",
          selected = prop_value.value
        }
      elseif prop_value.type == "number" then
        dlg:number{
          id = id_prefix .. "value",
          label = "Value:",
          text = tostring(prop_value.value),
          decimals = 0
        }
      else
        dlg:entry{
          id = id_prefix .. "value",
          label = "Value:",
          text = tostring(prop_value.value)
        }
      end

      dlg:button{
        id = id_prefix .. "delete",
        text = "Delete",
        onclick = function()
          sync_from_dialog(dlg)
          table.remove(properties, i)
          rebuild_from_dialog(dlg)
        end
      }
      dlg:newrow()
    end

    dlg:separator()

    dlg:button{
      id = "add_btn",
      text = "Add Property",
      onclick = function()
        sync_from_dialog(dlg)
        table.insert(properties, {
          key = "",
          type = "string",
          value = ""
        })
        rebuild_from_dialog(dlg)
      end
    }

    dlg:button{
      text = "Apply Changes",
      onclick = function()
        sync_from_dialog(dlg)
        local new_props = {}
        for _, prop in ipairs(properties) do
          if prop.key and prop.key ~= "" then
            table.insert(new_props, prop)
          end
        end
        set_tile_properties(tileset, tile_index, new_props)
      end
    }

    dlg:separator()

    dlg:button{
      text = "OK",
      focus = true,
      onclick = function()
        sync_from_dialog(dlg)
        local new_props = {}
        for _, prop in ipairs(properties) do
          if prop.key and prop.key ~= "" then
            table.insert(new_props, prop)
          end
        end
        set_tile_properties(tileset, tile_index, new_props)
        dlg:close()
      end
    }

    dlg:button{ text = "Cancel" }

    return dlg
  end

  function sync_from_dialog(dlg)
    log("sync_from_dialog() called")
    for i = 1, #properties do
      local id_prefix = "prop_" .. i .. "_"
      local data = dlg.data

      log("  Property " .. i .. ":")
      if data[id_prefix .. "key"] then
        properties[i].key = data[id_prefix .. "key"]
        log("    key = " .. tostring(properties[i].key))
      end
      if data[id_prefix .. "type"] then
        properties[i].type = data[id_prefix .. "type"]
        log("    type = " .. tostring(properties[i].type))
      end
      if data[id_prefix .. "value"] ~= nil then
        properties[i].value = data[id_prefix .. "value"]
        log("    value = " .. tostring(properties[i].value) .. " (type: " .. type(properties[i].value) .. ")")
      else
        log("    WARNING: value is nil in dialog data!")
      end
    end
  end

  function rebuild_from_dialog(old_dlg)
    old_dlg:close()
    local new_dlg = build_dialog()
    new_dlg:show()
  end

  local dlg = build_dialog()
  dlg:show()
end

function init(plugin)
  if not plugin then
    print("[tile-properties] ERROR: plugin is nil!")
    return
  end

  plugin:newCommand{
    id = "TilePropertiesEditor",
    title = "Tile Properties",
    group = "sprite_properties",
    onenabled = function()
      local tileset, tile_index = get_selected_tile()
      return tileset ~= nil and tile_index ~= nil
    end,
    onclick = show_property_editor
  }
end

function exit(plugin)
end
