defmodule Berrypod.Media.Image do
  use Ecto.Schema
  import Ecto.Changeset

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

  schema "images" do
    field :image_type, :string
    field :filename, :string
    field :content_type, :string
    field :file_size, :integer
    field :data, :binary
    field :is_svg, :boolean, default: false
    field :svg_content, :string
    field :source_width, :integer
    field :source_height, :integer
    field :variants_status, :string, default: "pending"
    field :alt, :string
    field :caption, :string
    field :tags, :string
    field :dominant_colors, :string

    timestamps(type: :utc_datetime)
  end

  @max_file_size 10_000_000

  @doc false
  def changeset(image, attrs) do
    image
    |> cast(attrs, [
      :image_type,
      :filename,
      :content_type,
      :file_size,
      :data,
      :is_svg,
      :svg_content,
      :source_width,
      :source_height,
      :variants_status,
      :alt,
      :caption,
      :tags,
      :dominant_colors
    ])
    |> validate_required([:image_type, :filename, :content_type, :file_size, :data])
    |> validate_inclusion(:image_type, ~w(logo header product icon media review))
    |> validate_number(:file_size, less_than: @max_file_size)
    |> detect_svg()
  end

  @doc "Changeset for editing metadata only (alt, caption, tags)."
  def metadata_changeset(image, attrs) do
    image
    |> cast(attrs, [:alt, :caption, :tags])
  end

  defp detect_svg(changeset) do
    content_type = get_change(changeset, :content_type)

    if content_type == "image/svg+xml" or
         String.ends_with?(get_change(changeset, :filename) || "", ".svg") do
      changeset
      |> put_change(:is_svg, true)
      |> maybe_store_svg_content()
    else
      changeset
    end
  end

  defp maybe_store_svg_content(changeset) do
    case get_change(changeset, :data) do
      nil ->
        changeset

      svg_binary when is_binary(svg_binary) ->
        put_change(changeset, :svg_content, svg_binary)
    end
  end
end
