defmodule SimpleshopTheme.ProductsUpsertTest do
  use SimpleshopTheme.DataCase, async: false

  alias SimpleshopTheme.Products

  import SimpleshopTheme.ProductsFixtures

  describe "upsert_product/2" do
    test "creates a new product when it doesn't exist" do
      conn = provider_connection_fixture()

      attrs = %{
        provider_product_id: "new-product-123",
        title: "New Product",
        description: "A new product",
        provider_data: %{"blueprint_id" => 145}
      }

      assert {:ok, product, :created} = Products.upsert_product(conn, attrs)
      assert product.title == "New Product"
      assert product.provider_product_id == "new-product-123"
    end

    test "returns unchanged when checksum matches" do
      conn = provider_connection_fixture()
      provider_data = %{"blueprint_id" => 145, "data" => "same"}

      {:ok, original, :created} =
        Products.upsert_product(conn, %{
          provider_product_id: "product-123",
          title: "Product",
          provider_data: provider_data
        })

      # Same provider_data = same checksum
      {:ok, product, :unchanged} =
        Products.upsert_product(conn, %{
          provider_product_id: "product-123",
          title: "Product Updated",
          provider_data: provider_data
        })

      assert product.id == original.id
      # Title should NOT be updated since checksum matched
      assert product.title == "Product"
    end

    test "updates product when checksum differs" do
      conn = provider_connection_fixture()

      {:ok, original, :created} =
        Products.upsert_product(conn, %{
          provider_product_id: "product-123",
          title: "Product",
          provider_data: %{"version" => 1}
        })

      # Different provider_data = different checksum
      {:ok, product, :updated} =
        Products.upsert_product(conn, %{
          provider_product_id: "product-123",
          title: "Product Updated",
          provider_data: %{"version" => 2}
        })

      assert product.id == original.id
      assert product.title == "Product Updated"
    end

    test "handles race condition when two processes try to insert same product" do
      conn = provider_connection_fixture()
      provider_product_id = "race-condition-test-#{System.unique_integer()}"

      attrs = %{
        provider_product_id: provider_product_id,
        title: "Race Condition Product",
        provider_data: %{"test" => true}
      }

      # Simulate race condition by running concurrent inserts
      tasks =
        for _ <- 1..5 do
          Task.async(fn ->
            Products.upsert_product(conn, attrs)
          end)
        end

      results = Task.await_many(tasks, 5000)

      # All should succeed (no crashes)
      assert Enum.all?(results, fn
               {:ok, _product, status} when status in [:created, :unchanged] -> true
               _ -> false
             end)

      # Only one product should exist
      assert Products.count_products_for_connection(conn.id) >= 1

      # Verify we can fetch the product
      product = Products.get_product_by_provider(conn.id, provider_product_id)
      assert product.title == "Race Condition Product"
    end

    test "matches by slug when provider_product_id changes" do
      conn = provider_connection_fixture()

      # Create first product
      {:ok, product1, :created} =
        Products.upsert_product(conn, %{
          provider_product_id: "old-product-id",
          title: "Same Title Product",
          provider_data: %{"id" => 1}
        })

      assert product1.provider_product_id == "old-product-id"

      # Same title but different provider_product_id - matches by slug and updates
      {:ok, product2, :updated} =
        Products.upsert_product(conn, %{
          provider_product_id: "new-product-id",
          title: "Same Title Product",
          provider_data: %{"id" => 2}
        })

      # Should be the same product, with updated provider_product_id
      assert product2.id == product1.id
      assert product2.provider_product_id == "new-product-id"
      assert product2.slug == "same-title-product"
    end

    test "different titles create different slugs successfully" do
      conn = provider_connection_fixture()

      {:ok, product1, :created} =
        Products.upsert_product(conn, %{
          provider_product_id: "product-1",
          title: "First Product",
          provider_data: %{"id" => 1}
        })

      {:ok, product2, :created} =
        Products.upsert_product(conn, %{
          provider_product_id: "product-2",
          title: "Second Product",
          provider_data: %{"id" => 2}
        })

      assert product1.slug == "first-product"
      assert product2.slug == "second-product"
    end
  end
end
