defmodule SimpleshopTheme.Orders.OrderNotifierTest do
  use SimpleshopTheme.DataCase, async: true

  import Swoosh.TestAssertions
  import SimpleshopTheme.OrdersFixtures

  alias SimpleshopTheme.Orders
  alias SimpleshopTheme.Orders.OrderNotifier

  describe "deliver_order_confirmation/1" do
    test "sends confirmation with order details" do
      order =
        order_fixture(%{
          customer_email: "buyer@example.com",
          payment_status: "paid",
          shipping_address: %{
            "name" => "Jane Doe",
            "line1" => "42 Test Street",
            "city" => "London",
            "postal_code" => "SW1A 1AA",
            "country" => "GB"
          }
        })

      assert {:ok, _email} = OrderNotifier.deliver_order_confirmation(order)

      assert_email_sent(fn email ->
        assert email.to == [{"", "buyer@example.com"}]
        assert email.subject =~ "Order confirmed"
        assert email.subject =~ order.order_number
        assert email.text_body =~ order.order_number
        assert email.text_body =~ "Test product"
        assert email.text_body =~ "Jane Doe"
        assert email.text_body =~ "42 Test Street"
        assert email.text_body =~ "London"
      end)
    end

    test "includes item quantities and prices" do
      order =
        order_fixture(%{
          customer_email: "buyer@example.com",
          payment_status: "paid",
          quantity: 2,
          unit_price: 1500
        })

      assert {:ok, _email} = OrderNotifier.deliver_order_confirmation(order)

      assert_email_sent(fn email ->
        assert email.text_body =~ "2x Test product"
      end)
    end

    test "includes order total" do
      order =
        order_fixture(%{
          customer_email: "buyer@example.com",
          payment_status: "paid",
          unit_price: 2500
        })

      assert {:ok, _email} = OrderNotifier.deliver_order_confirmation(order)

      assert_email_sent(fn email ->
        assert email.text_body =~ "Total:"
      end)
    end

    test "skips when customer_email is nil" do
      order = order_fixture(%{customer_email: nil})

      # Override to nil since fixture sets a default
      {:ok, order} = Orders.update_order(order, %{customer_email: nil})

      assert {:ok, :no_email} = OrderNotifier.deliver_order_confirmation(order)
      assert_no_email_sent()
    end

    test "skips when customer_email is empty string" do
      order = order_fixture()
      {:ok, order} = Orders.update_order(order, %{customer_email: ""})

      assert {:ok, :no_email} = OrderNotifier.deliver_order_confirmation(order)
      assert_no_email_sent()
    end

    test "handles missing shipping address" do
      order = order_fixture(%{customer_email: "buyer@example.com", payment_status: "paid"})

      assert {:ok, _email} = OrderNotifier.deliver_order_confirmation(order)
      assert_email_sent(subject: "Order confirmed - #{order.order_number}")
    end
  end

  describe "deliver_shipping_notification/1" do
    test "sends notification with tracking info" do
      {order, _v, _p, _c} = submitted_order_fixture(%{customer_email: "buyer@example.com"})

      {:ok, order} =
        Orders.update_fulfilment(order, %{
          fulfilment_status: "shipped",
          tracking_number: "1Z999AA1",
          tracking_url: "https://ups.com/track/1Z999AA1",
          shipped_at: DateTime.utc_now() |> DateTime.truncate(:second)
        })

      assert {:ok, _email} = OrderNotifier.deliver_shipping_notification(order)

      assert_email_sent(fn email ->
        assert email.to == [{"", "buyer@example.com"}]
        assert email.subject =~ "Your order has shipped"
        assert email.subject =~ order.order_number
        assert email.text_body =~ "1Z999AA1"
        assert email.text_body =~ "https://ups.com/track/1Z999AA1"
      end)
    end

    test "handles missing tracking info gracefully" do
      {order, _v, _p, _c} = submitted_order_fixture(%{customer_email: "buyer@example.com"})

      {:ok, order} =
        Orders.update_fulfilment(order, %{
          fulfilment_status: "shipped",
          shipped_at: DateTime.utc_now() |> DateTime.truncate(:second)
        })

      assert {:ok, _email} = OrderNotifier.deliver_shipping_notification(order)

      assert_email_sent(fn email ->
        assert email.text_body =~ "Tracking details will follow"
      end)
    end

    test "includes tracking number without URL" do
      {order, _v, _p, _c} = submitted_order_fixture(%{customer_email: "buyer@example.com"})

      {:ok, order} =
        Orders.update_fulfilment(order, %{
          fulfilment_status: "shipped",
          tracking_number: "RM123456789GB",
          shipped_at: DateTime.utc_now() |> DateTime.truncate(:second)
        })

      assert {:ok, _email} = OrderNotifier.deliver_shipping_notification(order)

      assert_email_sent(fn email ->
        assert email.text_body =~ "RM123456789GB"
        assert not (email.text_body =~ "Tracking details will follow")
      end)
    end

    test "skips when customer_email is nil" do
      {order, _v, _p, _c} = submitted_order_fixture()
      {:ok, order} = Orders.update_order(order, %{customer_email: nil})

      assert {:ok, :no_email} = OrderNotifier.deliver_shipping_notification(order)
      assert_no_email_sent()
    end
  end
end
