defmodule Firehose.Test.FakeBlog do
  @moduledoc """
  A test double that implements the blog module interface,
  backed by an Agent so tests can control the post data.
  """

  use Agent

  @defaults [
    blog_id: :test_blog,
    title: "Test Blog",
    description: "A blog for tests",
    base_path: "/blog/test"
  ]

  def start(posts \\ [], opts \\ []) do
    opts = Keyword.merge(@defaults, opts)

    state = %{
      posts: posts,
      blog_id: opts[:blog_id],
      title: opts[:title],
      description: opts[:description],
      base_path: opts[:base_path]
    }

    case Agent.start(fn -> state end, name: __MODULE__) do
      {:ok, pid} ->
        {:ok, pid}

      {:error, {:already_started, pid}} ->
        Agent.update(__MODULE__, fn _ -> state end)
        {:ok, pid}
    end
  end

  defp get(key), do: Agent.get(__MODULE__, &Map.fetch!(&1, key))

  def blog_id, do: get(:blog_id)
  def title, do: get(:title)
  def description, do: get(:description)
  def base_path, do: get(:base_path)

  def all_posts_unfiltered do
    get(:posts)
    |> Enum.sort_by(& &1.date, {:desc, Date})
  end

  def unfiltered_posts do
    all_posts_unfiltered()
  end

  def all_posts do
    get(:posts)
    |> Enum.filter(& &1.published)
    |> Enum.sort_by(& &1.date, {:desc, Date})
  end

  def all_tags do
    all_posts()
    |> Enum.flat_map(& &1.tags)
    |> Enum.uniq()
    |> Enum.sort()
  end
end
