defmodule SimpleshopTheme.Providers.Provider do
  @moduledoc """
  Behaviour for POD provider integrations.

  Each provider (Printify, Gelato, Prodigi, etc.) implements this behaviour
  to provide a consistent interface for:

  - Testing connections
  - Fetching products
  - Submitting orders
  - Tracking order status

  ## Data Normalization

  Providers return normalized data structures:

  - Products are maps with keys: `title`, `description`, `provider_product_id`,
    `images`, `variants`, `category`, `provider_data`
  - Variants are maps with keys: `provider_variant_id`, `title`, `sku`, `price`,
    `cost`, `options`, `is_enabled`, `is_available`
  - Images are maps with keys: `src`, `position`, `alt`
  """

  alias SimpleshopTheme.Products.ProviderConnection

  @doc """
  Returns the provider type identifier (e.g., "printify", "gelato").
  """
  @callback provider_type() :: String.t()

  @doc """
  Tests the connection to the provider.

  Returns `{:ok, info}` with provider-specific info (e.g., shop name)
  or `{:error, reason}` if the connection fails.
  """
  @callback test_connection(ProviderConnection.t()) :: {:ok, map()} | {:error, term()}

  @doc """
  Fetches all products from the provider.

  Returns a list of normalized product maps.
  """
  @callback fetch_products(ProviderConnection.t()) :: {:ok, [map()]} | {:error, term()}

  @doc """
  Submits an order to the provider for fulfillment.

  Returns `{:ok, %{provider_order_id: String.t()}}` on success.
  """
  @callback submit_order(ProviderConnection.t(), order :: map()) ::
              {:ok, %{provider_order_id: String.t()}} | {:error, term()}

  @doc """
  Gets the current status of an order from the provider.
  """
  @callback get_order_status(ProviderConnection.t(), provider_order_id :: String.t()) ::
              {:ok, map()} | {:error, term()}

  @doc """
  Returns the provider module for a given provider type.

  Checks `:provider_modules` application config first, allowing test
  overrides via Mox. Falls back to hardcoded dispatch.
  """
  def for_type(type) do
    case Application.get_env(:simpleshop_theme, :provider_modules, %{}) do
      modules when is_map(modules) ->
        case Map.get(modules, type) do
          nil -> default_for_type(type)
          module -> {:ok, module}
        end

      _ ->
        default_for_type(type)
    end
  end

  defp default_for_type("printify"), do: {:ok, SimpleshopTheme.Providers.Printify}
  defp default_for_type("gelato"), do: {:error, :not_implemented}
  defp default_for_type("prodigi"), do: {:error, :not_implemented}
  defp default_for_type("printful"), do: {:error, :not_implemented}
  defp default_for_type(type), do: {:error, {:unknown_provider, type}}

  @doc """
  Returns the provider module for a provider connection.
  """
  def for_connection(%ProviderConnection{provider_type: type}) do
    for_type(type)
  end
end
