defmodule Mobilizon.Medias.Media do
  @moduledoc """
  Represents a media entity.
  """

  use Ecto.Schema

  import Ecto.Changeset

  alias Mobilizon.Actors.Actor
  alias Mobilizon.Discussions.Comment
  alias Mobilizon.Events.Event
  alias Mobilizon.Medias.File
  alias Mobilizon.Medias.Media.Metadata
  alias Mobilizon.Posts.Post

  @type t :: %__MODULE__{
          uuid: Ecto.UUID.t(),
          file: File.t(),
          metadata: Metadata.t(),
          actor: Actor.t()
        }

  @attrs [:actor_id, :uuid]

  schema "medias" do
    # We need read_after_writes because the uuid is generated by
    # the database gen_random_uuid() function
    field(:uuid, Ecto.UUID, read_after_writes: true)

    embeds_one(:file, File, on_replace: :update)

    embeds_one(:metadata, Metadata, on_replace: :update)

    belongs_to(:actor, Actor)
    has_many(:event_picture, Event, foreign_key: :picture_id)
    many_to_many(:events, Event, join_through: "events_medias")
    has_many(:posts_picture, Post, foreign_key: :picture_id)
    many_to_many(:posts, Post, join_through: "posts_medias")
    many_to_many(:comments, Comment, join_through: "comments_medias")

    timestamps()
  end

  @doc false
  @spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
  def changeset(%__MODULE__{} = media, attrs) do
    media
    |> cast(attrs, @attrs)
    |> cast_embed(:file)
    |> cast_embed(:metadata)
    |> unique_constraint(:uuid)
  end
end