defmodule Microwaveprop.Workers.IonosphereFetchWorker do
  @moduledoc """
  Polls GIRO DIDBase for real-time ionosonde measurements (foF2, foE,
  foEs, hmF2, MUFD) from a handful of CONUS stations. Drives the 144
  MHz sporadic-E and HF MUF scoring inputs.

  Runs on a ~10-minute cron — GIRO publishes each station at 7.5-minute
  cadence so a 10-minute poll guarantees we pick up every new sample
  within one cycle without hammering the endpoint.

  Pulls a 2-hour window each poll to catch any late-arriving samples
  and to be resilient to the occasional missed run. Upserts are
  idempotent on (station_code, valid_time).
  """

  use Oban.Worker,
    queue: :ionosphere,
    max_attempts: 3,
    unique: [period: 300, states: [:available, :scheduled, :executing, :retryable]]

  alias Microwaveprop.Ionosphere
  alias Microwaveprop.Ionosphere.GiroClient

  require Logger

  # CONUS stations that have been publishing reliably. Others (Boulder,
  # Wallops, Austin, Idaho, Point Arguello) are in the GIRO catalog but
  # intermittent — add them here once they come back online.
  @stations [
    %{code: "MHJ45", name: "Millstone Hill MA", lat: 42.6, lon: -71.5},
    %{code: "AL945", name: "Alpena MI", lat: 45.1, lon: -83.6}
  ]

  @lookback_seconds 2 * 3600

  @impl Oban.Worker
  def perform(%Oban.Job{}) do
    now = DateTime.truncate(DateTime.utc_now(), :second)
    from_dt = DateTime.add(now, -@lookback_seconds, :second)

    Enum.each(@stations, fn station ->
      fetch_and_upsert(station, from_dt, now)
    end)

    :ok
  end

  @doc false
  @spec stations() :: [map()]
  def stations, do: @stations

  defp fetch_and_upsert(%{code: code, name: name}, from_dt, to_dt) do
    case GiroClient.fetch(code, from_dt, to_dt) do
      {:ok, observations} ->
        {:ok, count} = Ionosphere.upsert_observations(code, observations)
        Logger.info("IonosphereFetch: #{code} (#{name}) upserted #{count} observations")

      {:error, reason} ->
        Logger.warning("IonosphereFetch: #{code} (#{name}) failed: #{inspect(reason)}")
    end
  end
end
