defmodule Berrypod.Sync.MockupEnricherTest do
  use Berrypod.DataCase, async: false

  alias Berrypod.Clients.Printful, as: Client
  alias Berrypod.Products
  alias Berrypod.Sync.MockupEnricher

  import Berrypod.ProductsFixtures

  @moduletag capture_log: true

  setup do
    conn =
      provider_connection_fixture(%{
        provider_type: "printful",
        config: %{"store_id" => "99999"}
      })

    product =
      product_fixture(%{
        provider_connection: conn,
        provider_data: %{
          "catalog_product_id" => 71,
          "artwork_url" => "https://files.cdn.printful.com/artwork.png",
          "color_variant_map" => %{"Black" => 4011, "Natural" => 4013}
        }
      })

    %{provider_conn: conn, product: product}
  end

  describe "perform/1 happy path" do
    test "creates product images from mockup results", %{
      provider_conn: conn,
      product: product
    } do
      stub_mockup_generator_success()

      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => product.id
        }
      }

      assert :ok = MockupEnricher.perform(job)

      # Hero colour gets extra angles, other colours get front only
      images = Products.list_product_images(product.id)
      assert length(images) > 0

      # Check images have color tags
      assert Enum.any?(images, fn img -> img.color == "Black" end)
    end
  end

  describe "perform/1 skip conditions" do
    test "skips when no artwork_url", %{provider_conn: conn} do
      product =
        product_fixture(%{
          provider_connection: conn,
          provider_data: %{
            "catalog_product_id" => 71,
            "color_variant_map" => %{"Black" => 4011}
          }
        })

      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => product.id
        }
      }

      assert :ok = MockupEnricher.perform(job)
      assert Products.list_product_images(product.id) == []
    end

    test "skips when no catalog_product_id", %{provider_conn: conn} do
      product =
        product_fixture(%{
          provider_connection: conn,
          provider_data: %{
            "artwork_url" => "https://example.com/art.png",
            "color_variant_map" => %{"Black" => 4011}
          }
        })

      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => product.id
        }
      }

      assert :ok = MockupEnricher.perform(job)
      assert Products.list_product_images(product.id) == []
    end

    test "skips when already enriched", %{provider_conn: conn, product: product} do
      # Create an existing color-tagged image to simulate prior enrichment
      Products.create_product_image(%{
        product_id: product.id,
        src: "https://example.com/existing.jpg",
        alt: "Front",
        color: "Black",
        position: 0
      })

      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => product.id
        }
      }

      assert :ok = MockupEnricher.perform(job)

      # Should still only have the one existing image
      images = Products.list_product_images(product.id)
      assert length(images) == 1
    end
  end

  describe "perform/1 error handling" do
    test "returns {:cancel, :not_found} when connection missing", %{product: product} do
      job = %Oban.Job{
        args: %{
          "provider_connection_id" => Ecto.UUID.generate(),
          "product_id" => product.id
        }
      }

      assert {:cancel, :not_found} = MockupEnricher.perform(job)
    end

    test "returns {:cancel, :not_found} when product missing", %{provider_conn: conn} do
      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => Ecto.UUID.generate()
        }
      }

      assert {:cancel, :not_found} = MockupEnricher.perform(job)
    end

    test "returns {:snooze, 60} on 429 rate limit", %{
      provider_conn: conn,
      product: product
    } do
      Req.Test.stub(Client, fn plug_conn ->
        Req.Test.json(plug_conn |> Plug.Conn.put_status(429), %{"error" => "rate limited"})
      end)

      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => product.id
        }
      }

      assert {:snooze, 60} = MockupEnricher.perform(job)
    end

    test "returns :ok on 400 unsupported product", %{
      provider_conn: conn,
      product: product
    } do
      Req.Test.stub(Client, fn plug_conn ->
        Req.Test.json(
          plug_conn |> Plug.Conn.put_status(400),
          %{"error" => "Product not supported"}
        )
      end)

      job = %Oban.Job{
        args: %{
          "provider_connection_id" => conn.id,
          "product_id" => product.id
        }
      }

      assert :ok = MockupEnricher.perform(job)
    end
  end

  describe "enqueue/3" do
    test "staggers jobs by delay_index", %{provider_conn: conn, product: product} do
      stub_mockup_generator_success()

      {:ok, job0} = MockupEnricher.enqueue(conn.id, product.id, 0)
      {:ok, job2} = MockupEnricher.enqueue(conn.id, product.id, 2)

      # Job 2 should be scheduled later than job 0
      assert DateTime.compare(job2.scheduled_at, job0.scheduled_at) == :gt
    end
  end

  # =============================================================================
  # Stub helpers
  # =============================================================================

  defp stub_mockup_generator_success do
    Req.Test.stub(Client, fn plug_conn ->
      case {plug_conn.method, plug_conn.request_path} do
        {"POST", "/mockup-generator/create-task/" <> _id} ->
          Req.Test.json(plug_conn, %{
            "code" => 200,
            "result" => %{"task_key" => "gt-test-123", "status" => "pending"}
          })

        {"GET", "/mockup-generator/task"} ->
          Req.Test.json(plug_conn, %{
            "code" => 200,
            "result" => %{
              "status" => "completed",
              "mockups" => [
                %{
                  "mockup_url" => "https://mockup.printful.com/front.jpg",
                  "extra" => [
                    %{
                      "url" => "https://mockup.printful.com/back.jpg",
                      "title" => "Back"
                    },
                    %{
                      "url" => "https://mockup.printful.com/left.jpg",
                      "title" => "Left"
                    }
                  ]
                }
              ]
            }
          })

        _ ->
          Req.Test.json(plug_conn, %{"data" => %{}})
      end
    end)
  end
end
