defmodule Microwaveprop.Workers.UserHomeQthLookupWorker do
  @moduledoc """
  Looks up a user's callsign via QRZ (with Google Maps fallback) and
  populates their home QTH fields if they're still empty.

  Enqueued automatically on `Accounts.register_user/1` and reusable for
  backfilling existing users via:

      Microwaveprop.Repo.all(
        from u in Microwaveprop.Accounts.User, where: is_nil(u.home_grid)
      )
      |> Enum.each(fn user ->
        %{user_id: user.id}
        |> Microwaveprop.Workers.UserHomeQthLookupWorker.new()
        |> Oban.insert()
      end)
  """

  use Oban.Worker, queue: :weather, max_attempts: 3

  alias Microwaveprop.Accounts
  alias Microwaveprop.Accounts.User
  alias Microwaveprop.Radio.CallsignClient
  alias Microwaveprop.Radio.Maidenhead
  alias Microwaveprop.Repo

  require Logger

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{"user_id" => user_id}}) do
    case Repo.get(User, user_id) do
      nil ->
        :ok

      %User{home_grid: grid} when is_binary(grid) and grid != "" ->
        # User already set their home QTH manually; don't overwrite.
        :ok

      %User{callsign: nil} ->
        :ok

      %User{callsign: callsign} = user ->
        do_lookup(user, callsign)
    end
  end

  defp do_lookup(user, callsign) do
    case CallsignClient.locate(callsign) do
      {:ok, %{lat: lat, lon: lon} = result} ->
        grid = result[:gridsquare] || Maidenhead.from_latlon(lat, lon, 10)
        attrs = %{"home_grid" => grid, "home_lat" => lat, "home_lon" => lon}

        case Accounts.update_user_home_qth(user, attrs) do
          {:ok, _user} ->
            :ok

          {:error, changeset} ->
            Logger.warning(
              "UserHomeQthLookupWorker save failed: callsign=#{inspect(callsign)} errors=#{inspect(changeset.errors)}"
            )

            :ok
        end

      {:error, reason} ->
        Logger.info("UserHomeQthLookupWorker lookup failed for #{inspect(callsign)}: #{inspect(reason)}")
        :ok
    end
  end
end
