defmodule SimpleshopThemeWeb.Plugs.VerifyPrintifyWebhook do
  @moduledoc """
  Verifies Printify webhook signatures using HMAC-SHA256.

  Expects:
  - Raw body cached in conn.assigns[:raw_body]
  - X-Pfy-Signature header in format "sha256={hex_digest}"
  - Webhook secret stored in provider connection config
  """

  import Plug.Conn
  require Logger

  alias SimpleshopTheme.Products

  def init(opts), do: opts

  def call(conn, _opts) do
    with {:ok, signature} <- get_signature(conn),
         {:ok, secret} <- get_webhook_secret(),
         :ok <- verify_signature(conn.assigns[:raw_body], secret, signature) do
      conn
    else
      {:error, reason} ->
        Logger.warning("Printify webhook verification failed: #{reason}")

        conn
        |> put_resp_content_type("application/json")
        |> send_resp(401, Jason.encode!(%{error: "Invalid signature"}))
        |> halt()
    end
  end

  defp get_signature(conn) do
    case get_req_header(conn, "x-pfy-signature") do
      ["sha256=" <> hex_digest] -> {:ok, hex_digest}
      [_other] -> {:error, :invalid_signature_format}
      [] -> {:error, :missing_signature}
    end
  end

  defp get_webhook_secret do
    case Products.get_provider_connection_by_type("printify") do
      %{config: %{"webhook_secret" => secret}} when is_binary(secret) and secret != "" ->
        {:ok, secret}

      _ ->
        {:error, :no_webhook_secret}
    end
  end

  defp verify_signature(body, secret, expected_hex) do
    computed =
      :crypto.mac(:hmac, :sha256, secret, body || "")
      |> Base.encode16(case: :lower)

    if Plug.Crypto.secure_compare(computed, String.downcase(expected_hex)) do
      :ok
    else
      {:error, :signature_mismatch}
    end
  end
end
