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

  import Mox
  import Berrypod.OrdersFixtures

  alias Berrypod.Orders
  alias Berrypod.Orders.FulfilmentStatusWorker
  alias Berrypod.Providers.MockProvider

  setup :verify_on_exit!

  setup do
    Application.put_env(:berrypod, :provider_modules, %{
      "printify" => MockProvider
    })

    on_exit(fn -> Application.delete_env(:berrypod, :provider_modules) end)
    :ok
  end

  describe "perform/1" do
    test "no-op when no submitted orders" do
      assert :ok = FulfilmentStatusWorker.perform(%Oban.Job{args: %{}})
    end

    test "updates status from submitted to processing" do
      {order, _variant, _product, _conn} = submitted_order_fixture()

      expect(MockProvider, :get_order_status, fn _conn, provider_order_id ->
        assert provider_order_id == order.provider_order_id

        {:ok,
         %{
           status: "processing",
           provider_status: "in-production",
           tracking_number: nil,
           tracking_url: nil,
           shipments: []
         }}
      end)

      assert :ok = FulfilmentStatusWorker.perform(%Oban.Job{args: %{}})

      updated = Orders.get_order(order.id)
      assert updated.fulfilment_status == "processing"
      assert updated.provider_status == "in-production"
    end

    test "sets tracking info when shipped" do
      {order, _variant, _product, _conn} = submitted_order_fixture()

      expect(MockProvider, :get_order_status, fn _conn, _pid ->
        {:ok,
         %{
           status: "shipped",
           provider_status: "shipped",
           tracking_number: "1Z999AA10123456784",
           tracking_url: "https://tracking.example.com/1Z999AA10123456784",
           shipments: []
         }}
      end)

      assert :ok = FulfilmentStatusWorker.perform(%Oban.Job{args: %{}})

      updated = Orders.get_order(order.id)
      assert updated.fulfilment_status == "shipped"
      assert updated.tracking_number == "1Z999AA10123456784"
      assert updated.tracking_url == "https://tracking.example.com/1Z999AA10123456784"
      assert updated.shipped_at != nil
    end

    test "handles provider error gracefully" do
      {_order, _variant, _product, _conn} = submitted_order_fixture()

      expect(MockProvider, :get_order_status, fn _conn, _pid ->
        {:error, {500, %{"message" => "Internal error"}}}
      end)

      # Should not raise, just log the error
      assert :ok = FulfilmentStatusWorker.perform(%Oban.Job{args: %{}})
    end
  end
end
