defmodule WhoNeedHelp.Trust.Report do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  schema "reports" do
    field :reason, Ecto.Enum,
      values: [
        :dangerous_request,
        :harassment,
        :fraud,
        :prohibited_item,
        :spam,
        :impersonation,
        :other
      ]

    field :details, :string
    field :status, Ecto.Enum, values: [:open, :reviewing, :resolved, :dismissed], default: :open
    field :resolution_note, :string
    field :reviewed_at, :utc_datetime
    belongs_to :reporter, WhoNeedHelp.Accounts.User
    belongs_to :reviewed_by, WhoNeedHelp.Accounts.User
    belongs_to :request, WhoNeedHelp.Help.HelpRequest
    belongs_to :assignment, WhoNeedHelp.Help.Assignment
    belongs_to :message, WhoNeedHelp.Messaging.Message
    belongs_to :activity, WhoNeedHelp.Activities.Activity
    belongs_to :activity_message, WhoNeedHelp.Activities.Message
    timestamps(type: :utc_datetime)
  end

  def changeset(report, attrs) do
    report
    |> cast(attrs, [
      :reason,
      :details,
      :request_id,
      :assignment_id,
      :message_id,
      :activity_id,
      :activity_message_id
    ])
    |> validate_required([:reason, :details, :reporter_id])
    |> validate_length(:details, min: 5, max: 2_000)
    |> validate_single_target()
    |> check_constraint(:request_id, name: :report_exactly_one_target)
  end

  def moderation_changeset(report, attrs) do
    report
    |> cast(attrs, [:status, :resolution_note, :reviewed_at, :reviewed_by_id])
    |> validate_required([:status, :reviewed_at, :reviewed_by_id])
    |> validate_length(:resolution_note, max: 2_000)
  end

  defp validate_single_target(changeset) do
    targets =
      [:request_id, :assignment_id, :message_id, :activity_id, :activity_message_id]
      |> Enum.count(&(not is_nil(get_field(changeset, &1))))

    if targets == 1,
      do: changeset,
      else: add_error(changeset, :request_id, "select exactly one report target")
  end
end
