defmodule MusicLibrary.Search do
  @moduledoc """
  Universal search functionality across Records and Artists.

  This module provides unified search across:
  - Records in Collection (purchased records)
  - Records in Wishlist (unpurchased records)
  - Artists
  """

  alias MusicLibrary.{Artists, Collection, RecordSets, Wishlist}

  @pagination Application.compile_env!(:music_library, :pagination)

  @type search_opts :: [limit: non_neg_integer()]

  @doc """
  Performs a universal search across all entity types.

  Returns a map with grouped results:
  - :collection - Records in the collection
  - :wishlist - Records in the wishlist
  - :artists - Artists
  """
  @spec universal_search(String.t(), search_opts()) :: map()
  def universal_search(query, opts \\ []) do
    limit = Keyword.get(opts, :limit, @pagination[:search_preview_limit])

    %{
      collection: search_collection(query, limit),
      wishlist: search_wishlist(query, limit),
      artists: search_artists(query, limit),
      record_sets: search_record_sets(query, limit)
    }
  end

  @doc """
  Searches records in the collection (purchased records).
  """
  @spec search_collection(String.t(), non_neg_integer()) :: [map()]
  def search_collection(query, limit \\ @pagination[:search_preview_limit]) do
    Collection.search_records(query, limit: limit)
  end

  @doc """
  Searches records in the wishlist (unpurchased records).
  """
  @spec search_wishlist(String.t(), non_neg_integer()) :: [map()]
  def search_wishlist(query, limit \\ @pagination[:search_preview_limit]) do
    Wishlist.search_records(query, limit: limit)
  end

  @doc """
  Searches artists by name.

  Searches across artist names in the artist_records table,
  returning distinct artists that match the query.
  """
  @spec search_artists(String.t(), non_neg_integer()) :: [map()]
  def search_artists(query, limit \\ @pagination[:search_preview_limit]) do
    Artists.search_by_name(query, limit)
  end

  @doc """
  Gets the count of search results for each category.

  Returns a map with counts for each category:
  - :collection_count
  - :wishlist_count
  - :artists_count
  """
  @spec search_counts(String.t()) :: map()
  def search_counts(query) do
    %{
      collection_count: Collection.search_records_count(query),
      wishlist_count: Wishlist.search_records_count(query),
      artists_count: search_artists_count(query),
      record_sets_count: RecordSets.count_record_sets(query)
    }
  end

  @doc """
  Searches record sets by name, description, and contained records.
  """
  @spec search_record_sets(String.t(), non_neg_integer()) :: [map()]
  def search_record_sets(query, limit \\ @pagination[:search_preview_limit]) do
    RecordSets.search_record_sets(query, limit: limit)
  end

  @doc """
  Gets the count of artists matching the search query.
  """
  @spec search_artists_count(String.t()) :: non_neg_integer()
  def search_artists_count(query) do
    Artists.search_by_name_count(query)
  end
end
