lib/layout/layout.ex

defmodule LayoutBuilder.Layout.Layout do
  use Ecto.Schema
  import Ecto.Changeset
  alias LayoutBuilder.Layout.Row

  @moduledoc """
  Layout represents a Layout built by the Layout Builder.
  """

  @type t() :: %__MODULE__{
    id: Ecto.UUID.t() | nil,
    name: String.t(),
    rows: list(Row.t()) | nil,
  }

  embedded_schema do
    field :name, :string
    embeds_many :rows, Row
  end

  def changeset(%__MODULE__{} = struct, attrs) do
    change(struct)
    |> changeset(attrs)
  end

  def changeset(%Ecto.Changeset{} = change, %__MODULE__{} = attrs) do
    changeset(change, Map.from_struct(attrs))
  end

  def changeset(%Ecto.Changeset{} = change, %{} = attrs) do
    change
    |> cast(attrs, [:name])
    |> cast_embed(:rows)
  end

  @spec add_col(__MODULE__.t(), Row.t()) ::__MODULE__.t()
  def add_col(%__MODULE__{} = layout, row) do
    id = row.id
    rows = Enum.map(layout.rows, fn
      %Row{id: ^id} = row -> Row.add_col(row)
      row -> row
    end)
    %__MODULE__{layout | rows: rows}
  end

  @spec add_row(__MODULE__.t()) :: __MODULE__.t()
  def add_row(%__MODULE__{} = layout) do
    %__MODULE__{layout | rows: layout.rows ++ [Row.build_row]}
  end
end