defmodule Mix.Tasks.Mobilizon.Actors.Utils do
  @moduledoc """
  Tools for generating usernames from display names
  """

  alias Mobilizon.Actors
  alias Mobilizon.Actors.Actor
  alias Mobilizon.Users.User

  @doc """
  Removes all spaces, accents, special characters and diacritics from a string to create a plain ascii username (a-z0-9_)

  See https://stackoverflow.com/a/37511463
  """
  @spec generate_username(String.t()) :: String.t()
  def generate_username(""), do: ""

  def generate_username(name) do
    name
    |> String.downcase()
    |> String.normalize(:nfd)
    |> String.replace(~r/[\x{0300}-\x{036f}]/u, "")
    |> String.replace(~r/ /, "_")
    |> String.replace(~r/[^a-z0-9_]/, "")
  end

  # Profile from name
  @spec username_and_name(String.t() | nil, String.t() | nil) :: {String.t(), String.t()}
  def username_and_name(nil, profile_name) do
    {generate_username(profile_name), profile_name}
  end

  def username_and_name(profile_username, nil) do
    {profile_username, profile_username}
  end

  def username_and_name(profile_username, profile_name) do
    {profile_username, profile_name}
  end

  def create_profile(%User{id: user_id}, username, name, options \\ []) do
    {username, name} = username_and_name(username, name)

    {:ok, %Actor{} = new_person} =
      Actors.new_person(
        %{preferred_username: username, user_id: user_id, name: name},
        Keyword.get(options, :default, true)
      )

    new_person
  end

  @spec create_group(Actor.t(), String.t(), String.t()) ::
          {:ok, Actor.t()} | {:error, Ecto.Changeset.t()}
  def create_group(%Actor{id: admin_id}, username, name) do
    {username, name} = username_and_name(username, name)

    Actors.create_group(%{creator_actor_id: admin_id, preferred_username: username, name: name})
  end
end