-- Driver: regression coverage for #203 "You can't fly to indigo plateau".
--
-- pret/pokered engine/menus/town_map.asm LoadTownMap_Fly cycles EVERY visited
-- fly destination, and Indigo Plateau is a normal Fly spot once reached (its
-- special-warp lands the player on the Plateau exterior, data/maps/
-- special_warps.asm).  The port's fly-list filter gated each entry on
-- Map.isOutdoor(def), which is tileset == "OVERWORLD" -- but Indigo Plateau's
-- map uses tileset "PLATEAU", so it was silently dropped from the fly cursor
-- even though it is visited, has a fly warp, and sits in flyOrder.  This driver
-- walks the party-menu FLY flow, asserts INDIGO_PLATEAU is a cyclable fly
-- destination, flies there, and lands on the Plateau exterior.

return function(game)
  local U = dofile("tests/drivers/util.lua")
  local Pokemon = require("src.pokemon.Pokemon")
  local Screens = require("src.ui.Screens")
  local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"

  -- Party slot 1 knows FLY.  Pokemon.movesAtLevel never grants FLY, so inject
  -- the move directly after construction (same setup as the #195 driver).
  local flyer = Pokemon.new(game.data, "PIDGEOT", 40)
  flyer.moves[1] = { id = "FLY", pp = 15 }
  game.save.party = { flyer }
  game.save.player.name = "bryan"
  game.save.inventory = game.save.inventory or {}
  game.save.inventory.THUNDERBADGE = true -- FLY submenu entry is badge-gated
  game.save.visited = {
    PALLET_TOWN = true, VIRIDIAN_CITY = true, INDIGO_PLATEAU = true,
  }

  -- Exercise the real visited-marking path (OverworldController marks any
  -- flyWarps TOWN visited on entry, Map.isFlyTown) by standing on the Plateau
  -- exterior first, then hop back to Pallet for a clean starting point.
  U.teleport(game, "INDIGO_PLATEAU", 9, 6, "down")
  U.wait(5)
  assert(game.save.visited.INDIGO_PLATEAU,
    "entering the Plateau exterior must mark INDIGO_PLATEAU visited")
  U.teleport(game, "PALLET_TOWN", 10, 8, "down")
  U.wait(5)

  -- open the party menu and pick FLY on slot 1 (submenu: FLY / STATS / SWITCH,
  -- field moves on top like start_sub_menus.asm -- #768)
  Screens.push(game, "PartyMenu")
  U.wait(5)
  U.tap(game, "a")    -- open the per-mon submenu, cursor on FLY
  U.wait(2)
  U.tap(game, "a")    -- choose FLY
  U.wait(5)

  local top = game.stack:top()
  U.shot(game, DIR .. "/fly_map_screen.png")
  U.wait(4) -- let the async png write land before any assert can quit us

  U.log("fly screen top screenId:", tostring(top and top.screenId),
        "fly=", tostring(top and top.fly), "mode=", tostring(top and top.mode))
  local isFlyMap = top ~= nil and top.fly == true
                   and top.locs ~= nil and top.mode ~= nil
  assert(isFlyMap,
    "FLY must open the TOWN MAP in fly mode (LoadTownMap_Fly), got screen '"
    .. tostring(top and top.screenId or "nil") .. "' fly="
    .. tostring(top and top.fly))

  -- KEY ASSERTION (the #203 bug): INDIGO_PLATEAU must be a cyclable fly
  -- destination.  Before the fix the isOutdoor gate drops the PLATEAU-tileset
  -- Plateau, so this list is missing it and the assert fails.
  local hasIndigo = false
  local listStr = {}
  for i, id in ipairs(top.flyMapIds or {}) do
    listStr[i] = id
    if id == "INDIGO_PLATEAU" then hasIndigo = true end
  end
  U.log("fly destinations:", table.concat(listStr, ", "))
  assert(hasIndigo,
    "INDIGO_PLATEAU must appear in the fly destination list (it is visited, "
    .. "has a fly warp, and is in flyOrder); got { "
    .. table.concat(listStr, ", ") .. " }")

  -- walk the cursor to INDIGO PLATEAU (banner reads "To INDIGO PLATEAU")
  local function selectedMap()
    return top.flyMapIds and top.flyMapIds[top.sel]
  end
  U.log("initial fly selection:", tostring(selectedMap()))
  local guard = 0
  while selectedMap() ~= "INDIGO_PLATEAU" and guard < 12 do
    U.tap(game, "down")
    U.wait(2)
    guard = guard + 1
  end
  assert(selectedMap() == "INDIGO_PLATEAU",
    "Up/Down must cycle the fly cursor to INDIGO_PLATEAU, landed on "
    .. tostring(selectedMap()))
  U.shot(game, DIR .. "/fly_indigo_selected.png")
  U.wait(4)

  -- A flies to the highlighted destination: flyTo departs (48-frame bird),
  -- then warps to the Plateau exterior.
  U.tap(game, "a")
  U.wait(3)
  assert(game.overworld and game.overworld.flyDest
         and game.overworld.flyDest.map == "INDIGO_PLATEAU",
    "pressing A on the fly map must start the departure to INDIGO_PLATEAU, got "
    .. tostring(game.overworld and game.overworld.flyDest
                and game.overworld.flyDest.map))

  -- past the bird sweep + warp transition: the player lands on the Plateau
  local landed = false
  for _ = 1, 240 do
    if game.overworld and game.overworld.map
       and game.overworld.map.id == "INDIGO_PLATEAU" then
      landed = true
      break
    end
    U.wait(1)
  end
  U.wait(6)
  U.shot(game, DIR .. "/fly_landed_indigo.png")
  U.wait(4)
  assert(landed, "Fly must land the player on INDIGO_PLATEAU, ended on "
    .. tostring(game.overworld and game.overworld.map and game.overworld.map.id))

  U.log("RESULT bug203 PASS")
end
