defmodule Berrypod.Orders.AbandonedCartEmailWorker do
  @moduledoc """
  Sends a single cart recovery email after an abandoned Stripe checkout session.

  Enqueued with a 1-hour delay from the webhook handler. Re-checks suppression
  and recent paid orders at send time in case anything changed in the interim.
  """

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

  alias Berrypod.Orders
  alias Berrypod.Orders.OrderNotifier

  require Logger

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{"abandoned_cart_id" => cart_id}}) do
    with {:cart, cart} when not is_nil(cart) <- {:cart, Orders.get_abandoned_cart(cart_id)},
         {:not_emailed, true} <- {:not_emailed, is_nil(cart.emailed_at)},
         {:suppression, :ok} <- {:suppression, Orders.check_suppression(cart.customer_email)},
         {:no_recent_order, false} <-
           {:no_recent_order, Orders.has_recent_paid_order?(cart.customer_email)},
         {:order, order} when not is_nil(order) <- {:order, Orders.get_order(cart.order_id)} do
      unsubscribe_url = build_unsubscribe_url(cart.customer_email)

      case OrderNotifier.deliver_cart_recovery(cart, order, unsubscribe_url) do
        {:ok, _} ->
          {:ok, _} = Orders.mark_abandoned_cart_emailed(cart)
          Logger.info("Cart recovery email sent to #{cart.customer_email}")
          :ok

        {:error, reason} ->
          Logger.error("Cart recovery email failed: #{inspect(reason)}")
          {:error, reason}
      end
    else
      {:cart, nil} ->
        Logger.warning("Cart recovery: abandoned cart #{cart_id} not found")
        {:cancel, :not_found}

      {:not_emailed, false} ->
        Logger.info("Cart recovery: already emailed for cart #{cart_id}")
        :ok

      {:suppression, :suppressed} ->
        Logger.info("Cart recovery: email suppressed for cart #{cart_id}")
        :ok

      {:no_recent_order, true} ->
        Logger.info("Cart recovery: recent paid order found, skipping #{cart_id}")
        :ok

      {:order, nil} ->
        Logger.warning("Cart recovery: order not found for cart #{cart_id}")
        {:cancel, :order_not_found}
    end
  end

  def enqueue(abandoned_cart_id) do
    %{abandoned_cart_id: abandoned_cart_id}
    |> new(schedule_in: 3600)
    |> Oban.insert()
  end

  defp build_unsubscribe_url(email) do
    token = Phoenix.Token.sign(BerrypodWeb.Endpoint, "email-unsub", email)
    BerrypodWeb.Endpoint.url() <> "/unsubscribe/" <> token
  end
end
