defmodule Kalevala.Verb.Conditions do
  @moduledoc """
  A verb is not allowed unless all conditions are met

  - `location` is an array of all allowed locations, one must match
  """

  @derive Jason.Encoder
  defstruct [:location]
end

defmodule Kalevala.Verb.Context do
  @moduledoc """
  Context for running a verb

  - `location` where the verb is taking place
  """

  @derive Jason.Encoder
  defstruct [:location]
end

defmodule Kalevala.Verb do
  @moduledoc """
  A verb is a discrete action that the player may perform

  Things like picking up or dropping items, stealing, etc.
  """

  @derive Jason.Encoder
  defstruct [:conditions, :icon, :key, :send, :text]

  def replace_variables(verbs, variables) do
    Enum.map(verbs, fn verb ->
      Enum.reduce(variables, verb, fn {key, value}, verb ->
        Map.put(verb, :send, String.replace(verb.send, "${#{key}}", value))
      end)
    end)
  end

  @doc """
  Check if a list of verbs contains a verb that matches the context
  """
  def has_matching_verb?(verbs, verb_key, context) do
    verb =
      Enum.find(verbs, fn verb ->
        verb.key == verb_key
      end)

    case verb != nil do
      true ->
        matches?(verb, context)

      false ->
        false
    end
  end

  @doc """
  Check if a verb matches the context
  """
  def matches?(verb, context) do
    matches_location?(verb.conditions, context)
  end

  @doc """
  Check if the location condition matches the context

  No location condition == all locations are good

      iex> Verb.matches_location?(%{location: ["room"]}, %{location: "room"})
      true

      iex> Verb.matches_location?(%{location: ["inventory/self"]}, %{location: "inventory/self"})
      true

      iex> Verb.matches_location?(%{location: ["inventory"]}, %{location: "inventory/self"})
      true
  """
  def matches_location?(%{location: locations}, context) do
    Enum.any?(locations, fn location ->
      String.starts_with?(context.location, location)
    end)
  end

  def matches_location?(_conditions, _context), do: true
end
