defmodule Blogex.Post do
  @moduledoc """
  Struct representing a single blog post.

  Posts are parsed from markdown files with frontmatter metadata.
  The filename determines the date and slug:

      priv/blog/engineering/2026/03-10-our-new-architecture.md

  Frontmatter example:

      %{
        title: "Our New Architecture",
        author: "Jane Doe",
        tags: ~w(elixir architecture),
        description: "How we rebuilt our platform"
      }
      ---
      Your markdown content here...
  """

  @enforce_keys [:id, :title, :author, :body, :description, :date]
  defstruct [
    :id,
    :title,
    :author,
    :body,
    :description,
    :date,
    :blog,
    :image,
    tags: [],
    published: true
  ]

  @type t :: %__MODULE__{
          id: String.t(),
          title: String.t(),
          author: String.t(),
          body: String.t(),
          description: String.t(),
          date: Date.t(),
          image: String.t() | nil,
          tags: [String.t()],
          blog: atom(),
          published: boolean()
        }

  @type visibility :: :draft | :scheduled | :live

  @doc "Returns the visibility of a post: :draft, :scheduled, or :live."
  def visibility(%__MODULE__{published: false}), do: :draft

  def visibility(%__MODULE__{published: true, date: date}) do
    if Date.after?(date, Date.utc_today()), do: :scheduled, else: :live
  end

  @doc "Returns days until a scheduled post goes live, or nil."
  def days_until_live(%__MODULE__{} = post) do
    case visibility(post) do
      :scheduled -> Date.diff(post.date, Date.utc_today())
      _ -> nil
    end
  end

  @doc """
  Build callback for NimblePublisher.

  Extracts the date from the filename path and merges with frontmatter attrs.
  The `blog` atom is injected by the parent Blog module.
  """
  def build(filename, attrs, body) do
    [year, month_day_id] =
      filename
      |> Path.rootname()
      |> Path.split()
      |> Enum.take(-2)

    [month, day, id] = String.split(month_day_id, "-", parts: 3)
    date = Date.from_iso8601!("#{year}-#{month}-#{day}")

    struct!(
      __MODULE__,
      [id: id, date: date, body: body] ++ Map.to_list(attrs)
    )
  end
end
