defmodule Microwaveprop.Buildings.Loader do
  @moduledoc """
  Lazily loads cached Microsoft footprint csv.gz tiles into the
  spatial `Microwaveprop.Buildings.Index`. Idempotent: a quadkey
  loaded once stays loaded for the lifetime of the BEAM.

  Tiles that haven't been pre-fetched are skipped with a debug log —
  the rover scorer falls back to terrain-only path analysis when the
  index is missing for a region.
  """

  alias Microwaveprop.Buildings.Index
  alias Microwaveprop.Buildings.MsFootprints
  alias Microwaveprop.Buildings.Parser

  require Logger

  @zoom 9

  @doc """
  Ensures every quadkey covering `bbox` has its csv.gz tile parsed
  into the index. Returns the list of quadkeys that were *attempted*
  (whether already loaded, freshly loaded, or missing on disk).
  """
  @spec ensure_loaded_for_bbox(map()) :: [String.t()]
  def ensure_loaded_for_bbox(bbox) do
    quadkeys = MsFootprints.quadkeys_for_bbox(bbox, @zoom)
    Enum.each(quadkeys, &ensure_loaded/1)
    quadkeys
  end

  @doc """
  Load a single quadkey. No-op if already loaded; logs and skips if
  the csv.gz file is missing on disk.
  """
  @spec ensure_loaded(String.t()) :: :ok
  def ensure_loaded(quadkey) do
    if Index.loaded?(quadkey) do
      :ok
    else
      do_load(quadkey)
    end
  end

  defp do_load(quadkey) do
    path = Path.join(MsFootprints.cache_dir(), "#{quadkey}.csv.gz")

    if File.exists?(path) do
      records = path |> Parser.parse_tile() |> Enum.to_list()
      Index.insert_records(records)
      Index.mark_loaded(quadkey)
      Logger.info("buildings index: loaded #{quadkey} (#{length(records)} polygons)")
    else
      Logger.debug("buildings index: tile #{quadkey} not on disk; skipping")
      Index.mark_loaded(quadkey)
    end

    :ok
  end
end
