defmodule Cog.Chat.Provider do

  alias Cog.Chat.Room
  alias Cog.Chat.User

  @moduledoc """
  This module describes the mandatory API each chat
  provider module must implement.
  """

  @callback start_link(args :: term) :: {:ok, pid} | {:error, term}

  @callback lookup_user(name :: String.t) :: {:ok, %User{}} | {:error, term}

  @callback lookup_room([name: String.t]) :: {:ok, %Room{}} | {:error, term}
  @callback lookup_room([id: String.t]) :: {:ok, %Room{}} | {:error, term}

  @callback list_joined_rooms :: {:ok, [%Room{}] | []} | {:error, term}

  @callback join(room :: String.t) :: :ok | {:error, term}

  @callback leave(room :: String.t) :: :ok | {:error, term}

  @callback send_message(target :: String.t, message :: String.t | List.t, metadata :: Cog.Chat.MessageMetadata.t) :: :ok | {:ok, sent_message ::String.t} | {:error, term}

  @callback mention_name(handle :: String.t) :: String.t

  @callback display_name :: String.t

  defmacro __using__(_) do
    quote do
      @behaviour unquote(__MODULE__)

      alias Cog.Chat.Room
      alias Cog.Chat.User

      def lookup_user(_handle), do: {:error, :not_implemented}
      def lookup_room(_id), do: {:error, :not_implemented}
      def list_joined_rooms, do: {:error, :not_implemented}
      def join(_room), do: {:error, :not_implemented}
      def leave(_room), do: {:error, :not_implemented}
      def send_message(_target, _message, _metadata), do: {:error, :not_implemented}

      # TODO: Need to look into how useful this is... the new Slack
      # provider at least seems to not end up interpreting this as a
      # "mention" when included in output.
      #
      # Perhaps adding this directly into the Cog.Chat.User struct
      # would be useful.
      def mention_name(handle),
        do: "@" <> handle

      def display_name,
        do: __MODULE__ |> Module.split |> List.last

      defoverridable [lookup_user: 1,
                      lookup_room: 1,
                      list_joined_rooms: 0,
                      join: 1,
                      leave: 1,
                      send_message: 3,
                      mention_name: 1,
                      display_name: 0]
    end
  end


end
