defmodule LastFm.Artist do
  use Ecto.Schema

  import Ecto.Changeset

  @type t :: %__MODULE__{
          musicbrainz_id: String.t(),
          name: String.t(),
          summary: String.t(),
          bio: String.t(),
          image: String.t(),
          play_count: non_neg_integer(),
          base_url: String.t(),
          image_data_hash: String.t() | nil
        }

  @primary_key false
  embedded_schema do
    field :musicbrainz_id, :string
    field :name, :string
    field :summary, :string
    field :bio, :string
    field :image, :string
    field :play_count, :integer, default: 0
    field :base_url, :string
    field :image_data_hash, :string
  end

  @spec from_api_response(map()) :: t()
  def from_api_response(api_response) do
    %__MODULE__{
      musicbrainz_id: api_response["mbid"],
      name: api_response["name"],
      summary: api_response["bio"]["summary"] || "",
      bio: api_response["bio"]["content"] || "",
      image: get_image(api_response),
      play_count: get_play_count(api_response),
      base_url: api_response["url"]
    }
  end

  @spec changeset(t(), map()) :: Ecto.Changeset.t()
  def changeset(artist, attrs) do
    artist
    |> cast(attrs, [
      :musicbrainz_id,
      :name,
      :summary,
      :bio,
      :image,
      :play_count,
      :base_url
    ])
    |> validate_required([:name])
  end

  defp get_image(api_response) do
    api_response["image"]
    |> Enum.find(%{"#text" => nil}, fn i -> i["size"] == "medium" end)
    |> Map.get("#text")
  end

  defp get_play_count(api_response) do
    case get_in(api_response, ["stats", "userplaycount"]) do
      nil -> 0
      value -> parse_play_count(value)
    end
  end

  defp parse_play_count(value) when is_binary(value) do
    case Integer.parse(value) do
      {int, ""} -> int
      _ -> 0
    end
  end

  defp parse_play_count(_), do: 0
end
