defmodule Berrypod.Orders.FulfilmentStatusWorker do
  @moduledoc """
  Oban Cron worker that polls the fulfilment provider for status updates.

  Runs every 30 minutes as a fallback for missed webhook events.
  Only checks orders that are submitted or processing (i.e. awaiting
  further status transitions).
  """

  use Oban.Worker, queue: :sync, max_attempts: 1

  alias Berrypod.{ActivityLog, Orders}

  require Logger

  @impl Oban.Worker
  def perform(%Oban.Job{}) do
    orders = Orders.list_submitted_orders()

    if orders == [] do
      :ok
    else
      Logger.info("Polling fulfilment status for #{length(orders)} order(s)")

      Enum.each(orders, fn order ->
        refresh_order(order)
        Process.sleep(200)
      end)

      :ok
    end
  end

  defp refresh_order(order) do
    case Orders.refresh_fulfilment_status(order) do
      {:ok, updated} ->
        if updated.fulfilment_status != order.fulfilment_status do
          Logger.info(
            "Order #{order.order_number} status: #{order.fulfilment_status} → #{updated.fulfilment_status}"
          )

          log_status_change(order, updated)
        end

      {:error, reason} ->
        Logger.warning(
          "Failed to refresh status for order #{order.order_number}: #{inspect(reason)}"
        )
    end
  end

  defp log_status_change(order, updated) do
    {event_type, message, level, payload} =
      case updated.fulfilment_status do
        "processing" ->
          {"order.production", "In production", "info", %{}}

        "shipped" ->
          {"order.shipped", "Shipped#{tracking_suffix(updated)}", "info",
           %{tracking_number: updated.tracking_number, tracking_url: updated.tracking_url}}

        "delivered" ->
          {"order.delivered", "Delivered", "info", %{}}

        "failed" ->
          {"order.submission_failed",
           "Fulfilment failed: #{updated.fulfilment_error || "unknown error"}", "error",
           %{error: updated.fulfilment_error}}

        "cancelled" ->
          {"order.cancelled", "Order cancelled", "warning", %{}}

        other ->
          {"order.status_changed", "Status changed to #{other}", "info", %{}}
      end

    ActivityLog.log_event(event_type, message,
      level: level,
      order_id: order.id,
      payload: payload
    )
  end

  defp tracking_suffix(%{tracking_number: num}) when is_binary(num) and num != "" do
    " — tracking: #{num}"
  end

  defp tracking_suffix(_), do: ""
end
