defmodule Berrypod.Orders.AbandonedCartEmailWorkerTest do
  use Berrypod.DataCase, async: false

  import Swoosh.TestAssertions

  alias Berrypod.Orders
  alias Berrypod.Orders.AbandonedCartEmailWorker

  import Berrypod.OrdersFixtures

  defp build_cart(attrs \\ %{}) do
    order = order_fixture(%{customer_email: Map.get(attrs, :customer_email, "buyer@example.com")})

    defaults = %{
      customer_email: order.customer_email,
      order_id: order.id,
      stripe_session_id: "cs_#{System.unique_integer([:positive])}",
      cart_total: order.total,
      expired_at: DateTime.utc_now() |> DateTime.truncate(:second)
    }

    {:ok, cart} = Orders.create_abandoned_cart(Map.merge(defaults, attrs))
    {cart, order}
  end

  describe "perform/1 — sends email" do
    test "sends cart recovery email and marks as emailed" do
      {cart, _order} = build_cart()

      assert :ok =
               AbandonedCartEmailWorker.new(%{abandoned_cart_id: cart.id})
               |> Oban.insert!()
               |> then(fn job -> AbandonedCartEmailWorker.perform(job) end)

      assert_email_sent(subject: "You left something behind", to: cart.customer_email)

      updated = Orders.get_abandoned_cart(cart.id)
      assert not is_nil(updated.emailed_at)
    end

    test "does not send twice if already emailed" do
      {cart, _order} = build_cart()
      {:ok, cart} = Orders.mark_abandoned_cart_emailed(cart)

      AbandonedCartEmailWorker.perform(%Oban.Job{args: %{"abandoned_cart_id" => cart.id}})

      assert_no_email_sent()
    end

    test "skips send if email is suppressed" do
      {cart, _} = build_cart(%{customer_email: "suppressed@example.com"})
      Orders.add_suppression("suppressed@example.com", "unsubscribed")

      AbandonedCartEmailWorker.perform(%Oban.Job{args: %{"abandoned_cart_id" => cart.id}})

      assert_no_email_sent()
    end

    test "skips send if customer has a recent paid order" do
      {cart, _} = build_cart(%{customer_email: "recent@example.com"})
      order_fixture(%{customer_email: "recent@example.com", payment_status: "paid"})

      AbandonedCartEmailWorker.perform(%Oban.Job{args: %{"abandoned_cart_id" => cart.id}})

      assert_no_email_sent()
    end

    test "cancels if cart not found" do
      result =
        AbandonedCartEmailWorker.perform(%Oban.Job{
          args: %{"abandoned_cart_id" => Ecto.UUID.generate()}
        })

      assert {:cancel, :not_found} = result
      assert_no_email_sent()
    end
  end
end
