defmodule Web.CoreComponents do
  @moduledoc """
  Provides core UI components.
  """
  use Phoenix.Component

  attr :class, :string, default: nil
  attr :global, :global
  slot :inner_block

  def title(assigns) do
    ~H"""
    <h1 class={["font-bold text-xl mb-3", @class]} {@global}>{render_slot(@inner_block)}</h1>
    """
  end

  attr :class, :string, default: nil
  attr :global, :global
  slot :inner_block

  def subtitle(assigns) do
    ~H"""
    <h2 class={["font-bold text-lg mb-2", @class]} {@global}>{render_slot(@inner_block)}</h2>
    """
  end

  attr :class, :string, default: nil

  attr :global, :global,
    include: ~w[navigate patch href replace method csrf_token download hreflang referrerpolicy rel target type]

  slot :inner_block

  def a(assigns) do
    ~H"""
    <.link class={["hover:underline", @class]} {@global}>{render_slot(@inner_block)}</.link>
    """
  end

  attr :class, :string, default: nil
  attr :type, :string, default: "button"
  attr :global, :global
  slot :inner_block

  def button(assigns) do
    ~H"""
    <button type={@type} class={["hover:underline", @class]} {@global}>
      {render_slot(@inner_block)}
    </button>
    """
  end

  attr :class, :string, default: nil
  attr :field, Phoenix.HTML.FormField, required: true
  attr :type, :string, default: "text"
  attr :global, :global, include: ~w[required placeholder]

  def input(%{type: "textarea"} = assigns) do
    ~H"""
    <textarea
      class={["px-2 py-1 border border-gray-400 rounded", @class]}
      id={@field.id}
      name={@field.name}
      {@global}
    >{@field.value}</textarea>
    """
  end

  def input(assigns) do
    ~H"""
    <input
      class={["px-2 py-1 border border-gray-400 rounded", @class]}
      type={@type}
      id={@field.id}
      name={@field.name}
      value={@field.value}
      {@global}
    />
    """
  end

  @doc """
  Renders a [Heroicon](https://heroicons.com).

  Heroicons come in three styles – outline, solid, and mini.
  By default, the outline style is used, but solid and mini may
  be applied by using the `-solid` and `-mini` suffix.

  You can customize the size and colors of the icons by setting
  width, height, and background color classes.

  Icons are extracted from the `deps/heroicons` directory and bundled within
  your compiled app.css by the plugin in your `assets/tailwind.config.js`.

  ## Examples

      <.icon name="hero-x-mark-solid" />
      <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" />
  """
  attr :name, :string, required: true
  attr :class, :string, default: nil

  def icon(%{name: "hero-" <> _} = assigns) do
    ~H"""
    <span class={[@name, @class]} />
    """
  end

  attr :format, :string, required: true
  attr :value, :any, default: nil
  attr :formatter, :atom, default: :default
  attr :timezone, :string, default: "America/New_York"
  attr :global, :global

  def timex(%{value: nil} = assigns) do
    ~H"""
    <time datetime="">--</time>
    """
  end

  def timex(%{value: value, timezone: timezone} = assigns) do
    assigns =
      assign_new(assigns, :local_value, fn ->
        case value do
          %DateTime{} = datetime ->
            datetime

          %NaiveDateTime{} = naive ->
            naive
            |> DateTime.from_naive!("Etc/UTC")
            |> DateTime.shift_zone!(timezone)
        end
      end)

    ~H"""
    <time
      datetime={Timex.format!(@local_value, "{ISO:Extended}")}
      title={Timex.format!(@local_value, "{Mshort} {D}, {YYYY}, {h12}:{m} {AM} {Zabbr}")}
      {@global}
    >
      {Timex.format!(@local_value, @format, timex_formatter(@formatter))}
    </time>
    """
  end

  defp timex_formatter(formatter) do
    Module.concat(Timex.Format.DateTime.Formatters, :string.titlecase("#{formatter}"))
  end
end