defmodule MusicBrainz.Artist do
  @moduledoc false

  @enforce_keys [:id, :name, :sort_name]
  defstruct [:id, :name, :sort_name, :country, :relations, :musicbrainz_data]

  @type t :: %__MODULE__{
          id: String.t(),
          name: String.t(),
          sort_name: String.t(),
          country: String.t() | nil,
          relations: [map()] | nil,
          musicbrainz_data: map() | nil
        }

  @spec from_api_response(map()) :: t()
  def from_api_response(r) do
    %__MODULE__{
      id: r["id"],
      name: r["name"],
      sort_name: r["sort-name"],
      country: r["country"],
      relations: parse_relations(r["relations"] || []),
      musicbrainz_data: r
    }
  end

  # MASSIVE ASSUMPTION: if there's more than one Discogs link,
  # take the one with the lowest ID, as it's likely to be the main one.
  @spec get_discogs_id(t()) :: integer() | nil
  def get_discogs_id(r) do
    candidates =
      r.relations
      |> Enum.filter(fn relation ->
        relation.type == "discogs"
      end)
      |> Enum.map(fn relation ->
        parse_discogs_id(relation.url["resource"])
      end)
      |> Enum.sort()

    case candidates do
      [] -> nil
      [id | _rest] -> id
    end
  end

  @spec get_wikidata_id(t()) :: String.t() | nil
  def get_wikidata_id(r) do
    Enum.find_value(r.relations, fn relation ->
      if relation.type == "wikidata" do
        parse_wikidata_id(relation.url["resource"])
      end
    end)
  end

  @spec url(String.t()) :: String.t()
  def url(id) do
    "https://musicbrainz.org/artist/#{id}"
  end

  defp parse_relations(relations) do
    Enum.map(relations, fn relation ->
      %{
        type: relation["type"],
        url: relation["url"]
      }
    end)
  end

  defp parse_discogs_id("https://www.discogs.com/artist/" <> id) do
    case Integer.parse(id) do
      {int, ""} -> int
      _ -> nil
    end
  end

  defp parse_discogs_id(_other), do: nil

  defp parse_wikidata_id("https://www.wikidata.org/wiki/" <> id), do: id
  defp parse_wikidata_id(_other), do: nil
end
