defmodule Web.NavigationComponents do
  use Phoenix.Component
  use Web, :verified_routes
  import Web.CoreComponents

  attr :subject, :any, required: true

  def topbar(assigns) do
    ~H"""
    <nav class="bg-neutral-50 border-b border-neutral-200 px-4 py-2.5 fixed left-0 right-0 top-0 z-50">
      <div class="flex flex-wrap justify-between items-center">
        <div class="flex justify-start items-center">
          <button
            data-drawer-target="drawer-navigation"
            data-drawer-toggle="drawer-navigation"
            aria-controls="drawer-navigation"
            class={[
              "p-2 mr-2 text-neutral-600 rounded cursor-pointer md:hidden",
              "hover:text-neutral-900 hover:bg-neutral-100"
            ]}
          >
            <.icon name="hero-bars-3-center-left" class="w-6 h-6" />
            <span class="sr-only">Toggle sidebar</span>
          </button>
          <a
            href="https://www.firezone.dev/?utm_source=product"
            class="flex items-center justify-between mr-4"
          >
            <img src={~p"/images/logo.svg"} class="mr-3 h-8" alt="Firezone Logo" />
            <span class="self-center text-2xl font-medium whitespace-nowrap">
              Firezone
            </span>
          </a>
        </div>
        <div class="flex items-center lg:order-2">
          <.dropdown id="user-menu">
            <:button>
              <span class="sr-only">Open user menu</span>
              <.gravatar size={25} email={get_identity_email(@subject.identity)} class="rounded-full" />
            </:button>
            <:dropdown>
              <.subject_dropdown subject={@subject} />
            </:dropdown>
          </.dropdown>
        </div>
      </div>
    </nav>
    """
  end

  attr :subject, :any, required: true

  def subject_dropdown(assigns) do
    ~H"""
    <div class="py-3 px-4">
      <span class="block text-sm font-medium text-neutral-900">
        <%= @subject.actor.name %>
      </span>
      <span class="block text-sm text-neutral-900 truncate">
        <%= @subject.identity.provider_identifier %>
      </span>
    </div>
    <ul class="py-1 text-neutral-700" aria-labelledby="user-menu-dropdown">
      <li>
        <.link navigate={~p"/#{@subject.account}/actors/#{@subject.actor}"} class={~w[
          block py-2 px-4 text-sm hover:bg-neutral-100
        ]}>
          Profile
        </.link>
      </li>
    </ul>
    <ul class="py-1 text-neutral-700" aria-labelledby="user-menu-dropdown">
      <li>
        <a
          href={~p"/#{@subject.account}/sign_out"}
          class="block py-2 px-4 text-sm hover:bg-neutral-100"
        >
          Sign out
        </a>
      </li>
    </ul>
    """
  end

  slot :bottom, required: false

  slot :inner_block,
    required: true,
    doc: "The items for the navigation bar should use `sidebar_item` component."

  def sidebar(assigns) do
    ~H"""
    <aside class={~w[
        fixed top-0 left-0 z-40
        w-64 h-screen
        pt-14 pb-8
        transition-transform -translate-x-full
        bg-white border-r border-neutral-200
        md:translate-x-0
      ]} aria-label="Sidenav" id="drawer-navigation">
      <div class="overflow-y-auto py-1 px-1 h-full bg-white">
        <ul>
          <%= render_slot(@inner_block) %>
        </ul>
      </div>
      <%= render_slot(@bottom) %>
    </aside>
    """
  end

  attr :id, :string, required: true, doc: "ID of the nav group container"
  slot :button, required: true
  slot :dropdown, required: true

  def dropdown(assigns) do
    ~H"""
    <button
      type="button"
      class={["flex mx-3 text-sm bg-neutral-800 rounded-full md:mr-0"]}
      id={"#{@id}-button"}
      aria-expanded="false"
      data-dropdown-toggle={"#{@id}-dropdown"}
    >
      <%= render_slot(@button) %>
    </button>
    <div
      class={[
        "hidden",
        "z-50 my-4 w-56 text-base list-none bg-white rounded",
        "divide-y divide-neutral-100 shadow",
        "rounded-xl"
      ]}
      id={"#{@id}-dropdown"}
    >
      <%= render_slot(@dropdown) %>
    </div>
    """
  end

  attr :icon, :string, required: true
  attr :navigate, :string, required: true
  slot :inner_block, required: true
  attr :current_path, :string, required: true
  attr :active_class, :string, required: false, default: "bg-neutral-100"

  def sidebar_item(assigns) do
    ~H"""
    <li>
      <.link navigate={@navigate} class={~w[
      flex items-center p-2
      text-base text-neutral-900
      rounded
      #{sidebar_item_active?(@current_path, @navigate) && @active_class}
      hover:bg-neutral-100
      group]}>
        <.icon name={@icon} class={~w[
          w-6 h-6
          text-neutral-700
          transition duration-75
          group-hover:text-neutral-900
        ]} />
        <span class="ml-3"><%= render_slot(@inner_block) %></span>
      </.link>
    </li>
    """
  end

  defp sidebar_item_active?(current_path, destination_path) do
    [_, _slug_or_id, current_subpath] = String.split(current_path, "/", parts: 3)
    [_, _slug_or_id, destination_subpath] = String.split(destination_path, "/", parts: 3)
    String.starts_with?(current_subpath, destination_subpath)
  end

  attr :id, :string, required: true, doc: "ID of the nav group container"
  attr :icon, :string, required: true
  attr :current_path, :string, required: true
  attr :active_class, :string, required: false, default: "bg-neutral-100"

  slot :name, required: true

  slot :item, required: true do
    attr :navigate, :string, required: true
  end

  def sidebar_item_group(assigns) do
    dropdown_hidden =
      !Enum.any?(assigns.item, fn item ->
        String.starts_with?(assigns.current_path, item.navigate)
      end)

    assigns = assign(assigns, dropdown_hidden: dropdown_hidden)

    ~H"""
    <li>
      <button
        type="button"
        class={~w[
          flex items-center p-2 w-full group rounded
          text-base text-neutral-900
          transition duration-75
          hover:bg-neutral-100]}
        aria-controls={"dropdown-#{@id}"}
        data-collapse-toggle={"dropdown-#{@id}"}
        aria-hidden={@dropdown_hidden}
      >
        <.icon name={@icon} class={~w[
          w-6 h-6 text-neutral-800
          transition duration-75
          group-hover:text-neutral-900]} />
        <span class="flex-1 ml-3 text-left whitespace-nowrap"><%= render_slot(@name) %></span>
        <.icon name="hero-chevron-down-solid" class={~w[
          w-6 h-6 text-neutral-500
          transition duration-75
          group-hover:text-neutral-900]} />
      </button>
      <ul id={"dropdown-#{@id}"} class={if @dropdown_hidden, do: "hidden", else: ""}>
        <li :for={item <- @item}>
          <.link navigate={item.navigate} class={~w[
              flex items-center p-2 pl-11 w-full group rounded
              text-base text-neutral-900
              #{String.starts_with?(@current_path, item.navigate) && @active_class}
              transition duration-75
              hover:bg-neutral-100]}>
            <%= render_slot(item) %>
          </.link>
        </li>
      </ul>
    </li>
    """
  end

  @doc """
  Renders breadcrumbs section, for elements `<.breadcrumb />` component should be used.
  """
  attr :account, :any,
    required: false,
    default: nil,
    doc: "Account assign which will be used to fetch the home path."

  slot :inner_block, required: true, doc: "Breadcrumb entries"

  def breadcrumbs(assigns) do
    ~H"""
    <nav class="py-3 px-4" class="flex" aria-label="Breadcrumb">
      <ol class="inline-flex items-center space-x-1 md:space-x-2">
        <li class="inline-flex items-center">
          <.link
            navigate={if @account, do: ~p"/#{@account}", else: @home_path}
            class="inline-flex items-center text-neutral-700 hover:text-neutral-900"
          >
            <.icon name="hero-home-solid" class="w-4 h-4 mr-2" /> Home
          </.link>

          <%= render_slot(@inner_block) %>
        </li>
      </ol>
    </nav>
    """
  end

  @doc """
  Renders a single breadcrumb entry. should be wrapped in <.breadcrumbs> component.
  """
  slot :inner_block, required: true, doc: "The label for the breadcrumb entry."
  attr :path, :string, default: nil, doc: "The path for the breadcrumb entry."

  def breadcrumb(assigns) do
    ~H"""
    <li class="inline-flex items-center">
      <div class="flex items-center text-neutral-700">
        <.icon name="hero-chevron-right-solid" class="w-6 h-6" />
        <.link
          :if={not is_nil(@path)}
          navigate={@path}
          class="ml-1 text-neutral-700 hover:text-neutral-900 md:ml-2"
        >
          <%= render_slot(@inner_block) %>
        </.link>

        <span :if={is_nil(@path)} class="ml-1 text-sm text-neutral-700 hover:text-neutral-900 md:ml-2">
          <%= render_slot(@inner_block) %>
        </span>
      </div>
    </li>
    """
  end

  @doc """
  Renders a back navigation link.

  ## Examples

      <.back navigate={~p"/posts"}>Back to posts</.back>
  """
  attr :navigate, :any, required: true
  slot :inner_block, required: true

  def back(assigns) do
    ~H"""
    <div class="mt-16">
      <.link
        navigate={@navigate}
        class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700"
      >
        <.icon name="hero-arrow-left-solid" class="h-3 w-3" />
        <%= render_slot(@inner_block) %>
      </.link>
    </div>
    """
  end
end
