defmodule Sanbase.Project.SocialVolumeQuery do
  use Ecto.Schema

  import Ecto.Changeset
  alias Sanbase.Project

  @file_name "forbidden_social_volume_query_words.csv"
  @external_resource file = Path.join(__DIR__, @file_name)
  @forbidden_words File.read!(file)
                   |> String.split("\n")
                   |> Enum.uniq()
                   |> Enum.map(&String.downcase/1)
                   |> MapSet.new()

  schema "project_social_volume_query" do
    field(:query, :string)
    field(:autogenerated_query, :string)
    belongs_to(:project, Project)

    timestamps()
  end

  def changeset(%__MODULE__{} = query, attrs \\ %{}) do
    query
    |> cast(attrs, [:query, :project_id, :autogenerated_query])
    |> unique_constraint(:project_id)
  end

  def default_query_parts(%Project{} = project) do
    %Project{ticker: ticker, name: name, slug: slug} = project

    # Handle the case where when a project is hidden its name is set to Delete
    tokens =
      case String.downcase(name) do
        "delete" -> [ticker, slug]
        _ -> [ticker, name, slug]
      end

    tokens
    |> Enum.reject(&is_nil/1)
    |> Enum.map(&String.downcase/1)
    |> Enum.uniq()
    |> Enum.reject(&(&1 in @forbidden_words))
  end

  def default_query(%Project{} = project) do
    project
    |> default_query_parts()
    |> Enum.map(fn elem -> ~s/"#{elem}"/ end)
    |> Enum.join(" OR ")
  end
end

defimpl String.Chars, for: Sanbase.Project.SocialVolumeQuery do
  import Sanbase.Project.SocialVolumeQuery, only: [default_query: 1]

  def to_string(%{query: nil, project: project}) do
    default_query(project)
  end

  def to_string(%{query: query}) do
    query
  end
end
