defmodule BerrypodWeb.WebhookControllerTest do
  use BerrypodWeb.ConnCase

  import Berrypod.ProductsFixtures

  @webhook_secret "test_webhook_secret_123"

  setup do
    _conn =
      provider_connection_fixture(%{
        provider_type: "printify",
        config: %{"shop_id" => "12345", "webhook_secret" => @webhook_secret}
      })

    :ok
  end

  describe "POST /webhooks/printify" do
    test "returns 401 without signature", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> post(~p"/webhooks/printify", %{type: "product:updated"})

      assert json_response(conn, 401)["error"] == "Invalid signature"
    end

    test "returns 401 with invalid signature", %{conn: conn} do
      body = Jason.encode!(%{type: "product:updated", resource: %{id: "123"}})

      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pfy-signature", "sha256=invalid")
        |> post(~p"/webhooks/printify", body)

      assert json_response(conn, 401)["error"] == "Invalid signature"
    end

    test "accepts valid signature and returns 200", %{conn: conn} do
      body = Jason.encode!(%{type: "product:updated", resource: %{id: "123", shop_id: "12345"}})
      signature = compute_signature(body, @webhook_secret)

      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pfy-signature", "sha256=#{signature}")
        |> post(~p"/webhooks/printify", body)

      assert json_response(conn, 200)["status"] == "ok"
    end

    test "handles product:updated event", %{conn: conn} do
      body = Jason.encode!(%{type: "product:updated", resource: %{id: "123", shop_id: "12345"}})
      signature = compute_signature(body, @webhook_secret)

      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pfy-signature", "sha256=#{signature}")
        |> post(~p"/webhooks/printify", body)

      # Should return 200 even if job processing fails (inline mode tries to execute)
      assert json_response(conn, 200)["status"] == "ok"
    end

    test "handles product:deleted event", %{conn: conn} do
      body = Jason.encode!(%{type: "product:deleted", resource: %{id: "456"}})
      signature = compute_signature(body, @webhook_secret)

      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pfy-signature", "sha256=#{signature}")
        |> post(~p"/webhooks/printify", body)

      assert json_response(conn, 200)["status"] == "ok"
    end

    test "returns 401 when no webhook secret configured", %{conn: conn} do
      # Remove the provider connection to simulate no secret
      Berrypod.Repo.delete_all(Berrypod.Products.ProviderConnection)

      body = Jason.encode!(%{type: "product:updated", resource: %{id: "123"}})
      signature = compute_signature(body, @webhook_secret)

      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pfy-signature", "sha256=#{signature}")
        |> post(~p"/webhooks/printify", body)

      assert json_response(conn, 401)["error"] == "Invalid signature"
    end
  end

  defp compute_signature(body, secret) do
    :crypto.mac(:hmac, :sha256, secret, body)
    |> Base.encode16(case: :lower)
  end

  describe "POST /webhooks/printful" do
    @printful_secret "printful_test_secret_456"

    setup do
      _conn =
        provider_connection_fixture(%{
          provider_type: "printful",
          config: %{"store_id" => "99999", "webhook_secret" => @printful_secret}
        })

      :ok
    end

    test "returns 401 without token", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> post(~p"/webhooks/printful", %{type: "product_updated"})

      assert json_response(conn, 401)["error"] == "Invalid token"
    end

    test "returns 401 with wrong token", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pf-webhook-token", "wrong_token")
        |> post(~p"/webhooks/printful", %{type: "product_updated"})

      assert json_response(conn, 401)["error"] == "Invalid token"
    end

    test "accepts valid token via header", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pf-webhook-token", @printful_secret)
        |> post(~p"/webhooks/printful", %{type: "product_updated", data: %{}})

      assert json_response(conn, 200)["status"] == "ok"
    end

    test "accepts valid token via query param", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> post(~p"/webhooks/printful?token=#{@printful_secret}", %{
          type: "product_updated",
          data: %{}
        })

      assert json_response(conn, 200)["status"] == "ok"
    end

    test "handles unknown event gracefully", %{conn: conn} do
      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pf-webhook-token", @printful_secret)
        |> post(~p"/webhooks/printful", %{type: "unknown_event", data: %{}})

      assert json_response(conn, 200)["status"] == "ok"
    end

    test "returns 401 when no webhook secret configured", %{conn: conn} do
      Berrypod.Repo.delete_all(Berrypod.Products.ProviderConnection)

      conn =
        conn
        |> put_req_header("content-type", "application/json")
        |> put_req_header("x-pf-webhook-token", @printful_secret)
        |> post(~p"/webhooks/printful", %{type: "product_updated"})

      assert json_response(conn, 401)["error"] == "Invalid token"
    end
  end
end
