defmodule Blogex.LinkError do
  @moduledoc """
  Exception raised when a blog post contains invalid internal links.

  Raised at compile time by `Blogex.Blog` when `LinkValidator` finds
  semantic errors in post body links.

  ## Fields

    * `:blog` — the blog identifier atom (e.g., `:engineering`)
    * `:post_id` — the post slug/id that contains the invalid link
    * `:errors` — list of `{line, link, reason, post_id}` tuples

  ## Example

      raise Blogex.LinkError,
        blog: :engineering,
        post_id: "my-post",
        errors: [
          {1, "/blog/unknown/broken", "unknown blog ID: unknown", post_id: "my-post"}
        ]
  """

  defexception blog: nil, post_id: nil, errors: []

  @type t :: %__MODULE__{
          blog: atom(),
          post_id: String.t() | nil,
          errors: [{integer(), String.t(), String.t(), keyword()}]
        }

  @impl true
  def message(%__MODULE__{blog: blog, post_id: post_id, errors: errors}) do
    post_label =
      case post_id do
        nil -> ""
        id -> " (post: #{id})"
      end

    errors_list =
      errors
      |> Enum.map(fn {line, link, reason, _meta} ->
        "  line #{line}: #{link} — #{reason}"
      end)
      |> Enum.join("\n")

    """
    invalid internal blog links in #{blog}#{post_label}

    #{errors_list}
    """
  end
end
