defmodule SimpleshopTheme.Products.ProductVariant do
  @moduledoc """
  Schema for product variants.

  Variants represent different options (size, color, etc.) for a product.
  Each variant has its own pricing and availability.

  ## Options Field

  The `options` field stores variant options as a map with human-readable labels:

      %{
        "Size" => "Large",
        "Color" => "Navy Blue"
      }

  Labels are denormalized during sync for efficient display.
  """

  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  schema "product_variants" do
    field :provider_variant_id, :string
    field :title, :string
    field :sku, :string
    field :price, :integer
    field :compare_at_price, :integer
    field :cost, :integer
    field :options, :map, default: %{}
    field :is_enabled, :boolean, default: true
    field :is_available, :boolean, default: true

    belongs_to :product, SimpleshopTheme.Products.Product

    timestamps(type: :utc_datetime)
  end

  @doc """
  Changeset for creating or updating a product variant.
  """
  def changeset(product_variant, attrs) do
    product_variant
    |> cast(attrs, [
      :product_id,
      :provider_variant_id,
      :title,
      :sku,
      :price,
      :compare_at_price,
      :cost,
      :options,
      :is_enabled,
      :is_available
    ])
    |> validate_required([:product_id, :provider_variant_id, :title, :price])
    |> validate_number(:price, greater_than_or_equal_to: 0)
    |> validate_number(:compare_at_price, greater_than_or_equal_to: 0)
    |> validate_number(:cost, greater_than_or_equal_to: 0)
    |> unique_constraint([:product_id, :provider_variant_id])
    |> foreign_key_constraint(:product_id)
  end

  @doc """
  Returns the profit for this variant (price - cost).
  Returns nil if cost is not set.
  """
  def profit(%__MODULE__{price: price, cost: cost}) when is_integer(price) and is_integer(cost) do
    price - cost
  end

  def profit(_), do: nil

  @doc """
  Returns true if the variant is on sale (has a compare_at_price higher than price).
  """
  def on_sale?(%__MODULE__{price: price, compare_at_price: compare_at})
      when is_integer(price) and is_integer(compare_at) and compare_at > price do
    true
  end

  def on_sale?(_), do: false

  @doc """
  Formats the options as a human-readable title.
  E.g., %{"Size" => "Large", "Color" => "Blue"} -> "Large / Blue"
  """
  def options_title(%__MODULE__{options: options})
      when is_map(options) and map_size(options) > 0 do
    options
    |> Map.values()
    |> Enum.join(" / ")
  end

  def options_title(_), do: nil
end
