defmodule CodeCorps.GitHub.Adapters.Comment do
  @moduledoc ~S"""
  Used to convert between  GitHub data which represents a GitHub Issue Comment
  and `CodeCorps.Comment` as well as `CodeCorps.GithubComment` attributes.
  """

  alias CodeCorps.{
    Adapter.MapTransformer,
    Comment,
    GithubComment,
    GitHub.Adapters.Utils.BodyDecorator
  }

  @github_comment_to_comment_mapping [
    {:created_at, [:github_created_at]},
    {:markdown, [:body]},
    {:modified_at, [:github_updated_at]}
  ]

  @github_payload_to_comment_mapping [
    {:created_at, ["created_at"]},
    {:markdown, ["body"]},
    {:modified_at, ["updated_at"]}
  ]

  @github_payload_to_github_comment_mapping [
    {:body, ["body"]},
    {:github_created_at, ["created_at"]},
    {:github_id, ["id"]},
    {:github_updated_at, ["updated_at"]},
    {:html_url, ["html_url"]},
    {:url, ["url"]}
  ]

  @doc ~S"""
  Converts a `CodeCorps.GithubComment` into a set of attributes suitable for
  creating or updating a `CodeCorps.Comment`
  """
  @spec to_comment(GithubComment.t) :: map
  def to_comment(%GithubComment{} = github_comment) do
    github_comment
    |> Map.from_struct()
    |> BodyDecorator.remove_code_corps_header()
    |> MapTransformer.transform(@github_comment_to_comment_mapping)
  end

  @doc ~S"""
  Converts a GitHub Issue Comment payload into a set of attributes suitable for
  creating or updating a `CodeCorps.GithubComment`
  """
  @spec to_github_comment(map) :: map
  def to_github_comment(%{} = payload) do
    payload |> MapTransformer.transform(@github_payload_to_github_comment_mapping)
  end

  @autogenerated_github_keys ~w(created_at id updated_at)

  @doc ~S"""
  Converts a `CodeCorps.Comment` into a set of attributes suitable for creating
  or updating an GitHub Issue Comment through the GitHub API.
  """
  @spec to_api(Comment.t) :: map
  def to_api(%Comment{} = comment) do
    comment
    |> Map.from_struct
    |> MapTransformer.transform_inverse(@github_payload_to_comment_mapping)
    |> Map.drop(@autogenerated_github_keys)
    |> BodyDecorator.add_code_corps_header(comment)
  end
end
