defmodule BerrypodWeb.ShopComponents.Product do
  use Phoenix.Component

  import BerrypodWeb.ShopComponents.Base
  import BerrypodWeb.ShopComponents.Content, only: [responsive_image: 1, star_rating: 1]

  alias Berrypod.Products.{Product, ProductImage}
  alias BerrypodWeb.R

  @doc """
  Renders a product card with configurable variants.

  ## Attributes

  * `product` - Required. The product struct with `title`, `cheapest_price`, `images`, etc.
  * `theme_settings` - Required. The theme settings map.
  * `mode` - Either `:live` (default) or `:preview`.
  * `variant` - The visual variant:
    - `:default` - Collection page style with border, category, full details
    - `:featured` - Home page style with hover lift, no border
    - `:compact` - PDP related products with aspect-square, minimal info
    - `:minimal` - Error 404 style, smallest, not clickable
  * `show_category` - Show category label. Defaults based on variant.
  * `show_badges` - Show product badges. Defaults based on variant.
  * `show_delivery_text` - Show "Free delivery" text. Defaults based on variant.
  * `clickable` - Whether the card navigates. Defaults based on variant.

  ## Examples

      <.product_card product={product} theme_settings={@theme_settings} />
      <.product_card product={product} theme_settings={@theme_settings} variant={:featured} mode={:preview} />
  """
  attr :product, :map, required: true
  attr :theme_settings, :map, required: true
  attr :mode, :atom, default: :live
  attr :variant, :atom, default: :default
  attr :show_category, :boolean, default: nil
  attr :show_badges, :boolean, default: nil
  attr :show_delivery_text, :boolean, default: nil
  attr :clickable, :boolean, default: nil
  attr :priority, :boolean, default: false

  def product_card(assigns) do
    # Apply variant defaults for nil values
    defaults = variant_defaults(assigns.variant)

    assigns =
      assigns
      |> assign_new(:show_category_resolved, fn ->
        if assigns.show_category == nil, do: defaults.show_category, else: assigns.show_category
      end)
      |> assign_new(:show_badges_resolved, fn ->
        if assigns.show_badges == nil, do: defaults.show_badges, else: assigns.show_badges
      end)
      |> assign_new(:show_delivery_text_resolved, fn ->
        if assigns.show_delivery_text == nil,
          do: defaults.show_delivery_text,
          else: assigns.show_delivery_text
      end)
      |> assign_new(:clickable_resolved, fn ->
        if assigns.clickable == nil, do: defaults.clickable, else: assigns.clickable
      end)

    ~H"""
    <article
      class="product-card"
      data-variant={@variant}
      data-clickable={@clickable_resolved || nil}
    >
      <.product_card_inner
        product={@product}
        theme_settings={@theme_settings}
        variant={@variant}
        priority={@priority}
        show_category={@show_category_resolved}
        show_badges={@show_badges_resolved}
        show_delivery_text={@show_delivery_text_resolved}
        clickable={@clickable_resolved}
        mode={@mode}
      />
    </article>
    """
  end

  attr :product, :map, required: true
  attr :theme_settings, :map, required: true
  attr :variant, :atom, required: true
  attr :priority, :boolean, default: false
  attr :show_category, :boolean, required: true
  attr :show_badges, :boolean, required: true
  attr :show_delivery_text, :boolean, required: true
  attr :clickable, :boolean, default: true
  attr :mode, :atom, default: :live

  defp product_card_inner(assigns) do
    product = assigns.product
    primary_image = Product.primary_image(product)
    hover_image = Product.hover_image(product)

    product_url =
      if assigns.clickable && assigns.mode != :preview do
        R.product(Map.get(assigns.product, :slug) || Map.get(assigns.product, :id))
      end

    assigns =
      assigns
      |> assign(:primary_image, primary_image)
      |> assign(:hover_image, hover_image)
      |> assign(:has_hover_image, assigns.theme_settings.hover_image && hover_image != nil)
      |> assign(:product_url, product_url)

    ~H"""
    <.product_card_image_wrap href={@product_url}>
      <%= if @show_badges do %>
        <.product_badge product={@product} />
      <% end %>
      <%= if @has_hover_image do %>
        <div
          id={"product-image-scroll-#{Map.get(@product, :id, @product.title)}"}
          class="product-image-scroll"
          phx-hook="ProductImageScroll"
        >
          <.product_card_image
            image={@primary_image}
            alt={@product.title}
            variant={@variant}
            priority={@priority}
            class="product-image-primary"
          />
          <.product_card_image
            image={@hover_image}
            alt={@product.title}
            variant={@variant}
            class="product-image-hover"
          />
        </div>
      <% else %>
        <.product_card_image
          image={@primary_image}
          alt={@product.title}
          variant={@variant}
          priority={@priority}
          class="product-image-primary"
        />
      <% end %>
      <%= if @has_hover_image do %>
        <div class="product-image-dots" aria-hidden="true">
          <span class="product-image-dot product-image-dot-active"></span>
          <span class="product-image-dot"></span>
        </div>
      <% end %>
    </.product_card_image_wrap>
    <div class="product-card-content">
      <%= if @show_category && Map.get(@product, :category) do %>
        <%= if @mode == :preview do %>
          <p class="product-card-category">
            {@product.category}
          </p>
        <% else %>
          <.link
            patch={R.collection(Slug.slugify(@product.category))}
            class="product-card-category"
          >
            {@product.category}
          </.link>
        <% end %>
      <% end %>
      <h3 class="product-card-title">
        <%= if @clickable do %>
          <%= if @mode == :preview do %>
            <a
              href="#"
              phx-click="change_preview_page"
              phx-value-page="pdp"
              class="stretched-link"
            >
              {@product.title}
            </a>
          <% else %>
            <.link
              patch={R.product(Map.get(@product, :slug) || Map.get(@product, :id))}
              class="stretched-link"
            >
              {@product.title}
            </.link>
          <% end %>
        <% else %>
          {@product.title}
        <% end %>
      </h3>
      <%= if @theme_settings.show_prices do %>
        <.product_price product={@product} variant={@variant} />
      <% end %>
      <.product_card_rating product={@product} />
      <%= if @show_delivery_text do %>
        <p class="product-card-delivery">
          Made to order
        </p>
      <% end %>
    </div>
    """
  end

  attr :href, :string, default: nil
  slot :inner_block, required: true

  defp product_card_image_wrap(assigns) do
    ~H"""
    <%= if @href do %>
      <.link patch={@href} class="product-card-image-wrap" tabindex="-1" aria-hidden="true">
        {render_slot(@inner_block)}
      </.link>
    <% else %>
      <div class="product-card-image-wrap">
        {render_slot(@inner_block)}
      </div>
    <% end %>
    """
  end

  attr :image, :map, default: nil
  attr :alt, :string, required: true
  attr :variant, :atom, required: true
  attr :priority, :boolean, default: false
  attr :class, :string, default: ""

  defp product_card_image(assigns) do
    image = assigns.image

    {src, source_width} =
      cond do
        is_nil(image) ->
          {nil, nil}

        Map.get(image, :image_id) ->
          {"/image_cache/#{image.image_id}", ProductImage.source_width(image)}

        Map.get(image, :src) ->
          {Map.get(image, :src), ProductImage.source_width(image)}

        true ->
          {nil, nil}
      end

    assigns =
      assigns
      |> assign(:src, src)
      |> assign(:source_width, source_width)

    ~H"""
    <%= cond do %>
      <% is_nil(@src) -> %>
        <div
          class={[@class, "product-card-placeholder"]}
          role="img"
          aria-label={@alt}
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            stroke-width="1.5"
            stroke="currentColor"
            width="48"
            height="48"
            class="placeholder-icon"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909M3.75 21h16.5A2.25 2.25 0 0 0 22.5 18.75V5.25A2.25 2.25 0 0 0 20.25 3H3.75A2.25 2.25 0 0 0 1.5 5.25v13.5A2.25 2.25 0 0 0 3.75 21Zm16.5-13.5a1.125 1.125 0 1 1-2.25 0 1.125 1.125 0 0 1 2.25 0Z"
            />
          </svg>
        </div>
      <% @source_width -> %>
        <.responsive_image
          src={@src}
          alt={@alt}
          source_width={@source_width}
          sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
          class={@class}
          width={600}
          height={600}
          priority={@priority}
        />
      <% true -> %>
        <img
          src={@src}
          alt={@alt}
          width="600"
          height="600"
          loading={if @priority, do: nil, else: "lazy"}
          decoding={if @priority, do: nil, else: "async"}
          class={@class}
        />
    <% end %>
    """
  end

  attr :product, :map, required: true

  defp product_badge(assigns) do
    ~H"""
    <%= cond do %>
      <% Map.get(@product, :status) == "discontinued" -> %>
        <span class="product-badge badge-discontinued">Discontinued</span>
      <% Map.get(@product, :in_stock, true) == false -> %>
        <span class="product-badge badge-sold-out">Sold out</span>
      <% Map.get(@product, :is_new) -> %>
        <span class="product-badge badge-new">New</span>
      <% Map.get(@product, :on_sale) -> %>
        <span class="product-badge badge-sale">Sale</span>
      <% true -> %>
    <% end %>
    """
  end

  attr :product, :map, required: true
  attr :variant, :atom, required: true

  defp product_price(assigns) do
    ~H"""
    <%= case @variant do %>
      <% :default -> %>
        <div>
          <%= if @product.on_sale do %>
            <span class="product-price--sale">
              {Berrypod.Cart.format_price(@product.cheapest_price)}
            </span>
            <span class="product-price--compare">
              {Berrypod.Cart.format_price(@product.compare_at_price)}
            </span>
          <% else %>
            <span class="product-price--regular">
              {Berrypod.Cart.format_price(@product.cheapest_price)}
            </span>
          <% end %>
        </div>
      <% :featured -> %>
        <p class="product-price--secondary">
          <%= if @product.on_sale do %>
            <span class="product-price--compare">
              {Berrypod.Cart.format_price(@product.compare_at_price)}
            </span>
          <% end %>
          {Berrypod.Cart.format_price(@product.cheapest_price)}
        </p>
      <% :compact -> %>
        <p class="product-price--regular">
          {Berrypod.Cart.format_price(@product.cheapest_price)}
        </p>
      <% :minimal -> %>
        <p class="product-price--secondary">
          {Berrypod.Cart.format_price(@product.cheapest_price)}
        </p>
    <% end %>
    """
  end

  attr :product, :map, required: true

  defp product_card_rating(assigns) do
    rating_count = Map.get(assigns.product, :rating_count, 0)
    rating_avg = Map.get(assigns.product, :rating_avg)

    # Round to nearest integer for stars display
    rating_rounded =
      if rating_avg do
        rating_avg |> Decimal.round(0) |> Decimal.to_integer()
      else
        0
      end

    assigns =
      assigns
      |> assign(:rating_count, rating_count)
      |> assign(:rating_rounded, rating_rounded)

    ~H"""
    <div :if={@rating_count > 0} class="product-card-rating">
      <.star_rating rating={@rating_rounded} size={:sm} />
      <span class="product-card-rating-count">({@rating_count})</span>
    </div>
    """
  end

  defp variant_defaults(:default),
    do: %{show_category: true, show_badges: true, show_delivery_text: true, clickable: true}

  defp variant_defaults(:featured),
    do: %{show_category: false, show_badges: true, show_delivery_text: true, clickable: true}

  defp variant_defaults(:compact),
    do: %{show_category: false, show_badges: false, show_delivery_text: false, clickable: true}

  defp variant_defaults(:minimal),
    do: %{show_category: false, show_badges: false, show_delivery_text: false, clickable: false}

  @doc """
  Renders a responsive product grid container.

  This component wraps product cards in a responsive grid layout. It supports
  theme-based column settings or fixed column layouts for specific use cases.

  ## Attributes

  * `theme_settings` - Optional. When provided, uses `grid_columns` setting for lg breakpoint.
  * `columns` - Optional. Fixed column count for lg breakpoint (overrides theme_settings).
    Use `:fixed_4` for a fixed 2/4 column layout (error page, related products).
  * `gap` - Optional. Gap size. Defaults to standard gap.
  * `class` - Optional. Additional CSS classes to add.

  ## Slots

  * `inner_block` - Required. The product cards to render inside the grid.

  ## Examples

      <.product_grid theme_settings={@theme_settings}>
        <%= for product <- @products do %>
          <.product_card product={product} theme_settings={@theme_settings} />
        <% end %>
      </.product_grid>

      <.product_grid columns={:fixed_4}>
        ...
      </.product_grid>
  """
  attr :theme_settings, :map, default: nil
  attr :columns, :atom, default: nil
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def product_grid(assigns) do
    cols =
      cond do
        assigns.columns == :fixed_4 -> "fixed-4"
        assigns.theme_settings != nil -> assigns.theme_settings.grid_columns || "3"
        true -> "3"
      end

    assigns = assign(assigns, :data_columns, cols)

    ~H"""
    <div class={["product-grid", @class]} data-columns={@data_columns}>
      {render_slot(@inner_block)}
    </div>
    """
  end

  @doc """
  Renders a centered hero section with title, description, and optional CTAs.

  ## Attributes

  * `title` - Required. The main heading text.
  * `description` - Required. The description paragraph text.
  * `variant` - The visual variant:
    - `:default` - Standard hero with section wrapper and padding
    - `:page` - Page header style, larger title, more spacing, no section wrapper
    - `:error` - Error page with pre-title (404), two buttons
  * `background` - Background style. Either `:base` (default) or `:sunken`.
  * `pre_title` - Optional. Text shown above title (e.g., "404" for error pages).
  * `cta_text` - Optional. Text for the primary CTA button.
  * `cta_page` - Optional. Page to navigate to on click (for preview mode).
  * `cta_href` - Optional. URL for live mode navigation.
  * `secondary_cta_text` - Optional. Text for secondary button (error variant).
  * `secondary_cta_page` - Optional. Page for secondary button (preview mode).
  * `secondary_cta_href` - Optional. URL for secondary button (live mode).
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.hero_section
        title="Original designs, printed on demand"
        description="From art prints to apparel..."
        cta_text="Shop the collection"
        cta_page="collection"
        mode={:preview}
      />

      <.hero_section
        variant={:page}
        title="Get in touch"
        description="Questions about your order?"
      />

      <.hero_section
        variant={:error}
        pre_title="404"
        title="Page Not Found"
        description="Sorry, that page doesn't exist..."
        cta_text="Go to Homepage"
        secondary_cta_text="Browse Products"
        mode={:preview}
      />
  """
  attr :title, :string, required: true
  attr :description, :string, required: true
  attr :variant, :atom, default: :default
  attr :background, :atom, default: :base
  attr :pre_title, :string, default: nil
  attr :cta_text, :string, default: nil
  attr :cta_page, :string, default: nil
  attr :cta_href, :string, default: nil
  attr :secondary_cta_text, :string, default: nil
  attr :secondary_cta_page, :string, default: nil
  attr :secondary_cta_href, :string, default: nil
  attr :mode, :atom, default: :live

  def hero_section(assigns) do
    ~H"""
    <%= case @variant do %>
      <% :default -> %>
        <section class="hero-section" data-background={@background}>
          <h1 class="t-heading">
            {@title}
          </h1>
          <p class="hero-description">
            {@description}
          </p>
          <.hero_cta
            :if={@cta_text}
            text={@cta_text}
            page={@cta_page}
            href={@cta_href}
            mode={@mode}
            variant={:primary}
          />
        </section>
      <% :page -> %>
        <div class="hero-section--page">
          <h1 class="t-heading">
            {@title}
          </h1>
          <p class="hero-description">
            {@description}
          </p>
        </div>
      <% :error -> %>
        <div class="hero-error">
          <%= if @pre_title do %>
            <h1 class="hero-pre-title">
              {@pre_title}
            </h1>
          <% end %>
          <h2 class="t-heading">
            {@title}
          </h2>
          <p class="hero-description">
            {@description}
          </p>
          <%= if @cta_text || @secondary_cta_text do %>
            <div class="hero-cta-group">
              <.hero_cta
                :if={@cta_text}
                text={@cta_text}
                page={@cta_page}
                href={@cta_href}
                mode={@mode}
                variant={:primary}
              />
              <.hero_cta
                :if={@secondary_cta_text}
                text={@secondary_cta_text}
                page={@secondary_cta_page}
                href={@secondary_cta_href}
                mode={@mode}
                variant={:secondary}
              />
            </div>
          <% end %>
        </div>
    <% end %>
    """
  end

  attr :text, :string, required: true
  attr :page, :string, default: nil
  attr :href, :string, default: nil
  attr :mode, :atom, required: true
  attr :variant, :atom, required: true

  defp hero_cta(assigns) do
    base_class =
      case assigns.variant do
        :primary -> "themed-button hero-cta"
        :secondary -> "themed-button-outline hero-cta"
      end

    assigns = assign(assigns, :cta_class, base_class)

    ~H"""
    <%= if @mode == :preview do %>
      <button
        phx-click="change_preview_page"
        phx-value-page={@page}
        class={@cta_class}
      >
        {@text}
      </button>
    <% else %>
      <.link
        patch={@href || "/"}
        class={@cta_class}
      >
        {@text}
      </.link>
    <% end %>
    """
  end

  @doc """
  Renders a row of category circles for navigation.

  ## Attributes

  * `categories` - Required. List of category maps with `name` and `image_url`.
  * `limit` - Optional. Maximum number of categories to show. Defaults to 3.
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.category_nav categories={@categories} mode={:preview} />
      <.category_nav categories={@categories} limit={4} />
  """
  attr :categories, :list, required: true
  attr :limit, :integer, default: 3
  attr :mode, :atom, default: :live

  def category_nav(assigns) do
    ~H"""
    <section class="category-nav-section">
      <h2 class="sr-only">Shop by Category</h2>
      <nav class="category-nav" aria-label="Product categories">
        <%= for category <- Enum.take(@categories, @limit) do %>
          <%= if @mode == :preview do %>
            <a
              href="#"
              phx-click="change_preview_page"
              phx-value-page="collection"
              class="category-card"
            >
              <div
                class="category-image"
                style={
                  if(category[:image_url],
                    do: "background-image: url('#{category.image_url}');",
                    else: ""
                  )
                }
              >
              </div>
              <span class="category-name">
                {category.name}
              </span>
            </a>
          <% else %>
            <.link
              patch={R.collection(category.slug)}
              class="category-card"
            >
              <div
                class="category-image"
                style={
                  if(category[:image_url],
                    do: "background-image: url('#{category.image_url}');",
                    else: ""
                  )
                }
              >
              </div>
              <span class="category-name">
                {category.name}
              </span>
            </.link>
          <% end %>
        <% end %>
      </nav>
    </section>
    """
  end

  @doc """
  Renders a featured products section with title, product grid, and view-all button.

  ## Attributes

  * `title` - Required. Section heading text.
  * `products` - Required. List of products to display.
  * `theme_settings` - Required. The theme settings map.
  * `limit` - Optional. Maximum products to show. Defaults to 4.
  * `mode` - Either `:live` (default) or `:preview`.
  * `cta_text` - Optional. Text for the "view all" button. Defaults to "View all products".
  * `cta_page` - Optional. Page to navigate to (preview mode). Defaults to "collection".
  * `cta_href` - Optional. URL for live mode. Defaults to "/collections/all".

  ## Examples

      <.featured_products_section
        title="Featured products"
        products={@products}
        theme_settings={@theme_settings}
        mode={:preview}
      />
  """
  attr :title, :string, required: true
  attr :products, :list, required: true
  attr :theme_settings, :map, required: true
  attr :limit, :integer, default: 4
  attr :mode, :atom, default: :live
  attr :cta_text, :string, default: "View all products"
  attr :cta_page, :string, default: "collection"
  attr :cta_href, :string, default: "/collections/all"

  def featured_products_section(assigns) do
    ~H"""
    <section class="featured-section">
      <h2 class="t-heading">
        {@title}
      </h2>

      <.product_grid theme_settings={@theme_settings}>
        <%= for {product, idx} <- @products |> Enum.take(@limit) |> Enum.with_index() do %>
          <.product_card
            product={product}
            theme_settings={@theme_settings}
            mode={@mode}
            variant={:featured}
            priority={idx < 2}
          />
        <% end %>
      </.product_grid>

      <div class="featured-cta-wrap">
        <%= if @mode == :preview do %>
          <button
            phx-click="change_preview_page"
            phx-value-page={@cta_page}
            class="outline-button"
          >
            {@cta_text}
          </button>
        <% else %>
          <.link
            patch={@cta_href}
            class="outline-button"
          >
            {@cta_text}
          </.link>
        <% end %>
      </div>
    </section>
    """
  end

  @doc """
  Renders a two-column image + text section.

  ## Attributes

  * `title` - Required. Section heading text.
  * `description` - Required. Body text content.
  * `image_url` - Required. URL for the image.
  * `link_text` - Optional. Text for the link. If nil, no link is shown.
  * `link_page` - Optional. Page to navigate to (preview mode).
  * `link_href` - Optional. URL for live mode.
  * `image_position` - Either `:left` (default) or `:right`.
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.image_text_section
        title="Made with passion, printed with care"
        description="Every design starts with an idea..."
        image_url="/mockups/example.jpg"
        link_text="Learn more about the studio →"
        link_page="about"
        mode={:preview}
      />
  """
  attr :title, :string, required: true
  attr :description, :string, required: true
  attr :image_url, :string, required: true
  attr :link_text, :string, default: nil
  attr :link_page, :string, default: nil
  attr :link_href, :string, default: nil
  attr :image_position, :atom, default: :left
  attr :mode, :atom, default: :live

  def image_text_section(assigns) do
    ~H"""
    <section class="image-text-section">
      <%= if @image_position == :left do %>
        <.image_text_image image_url={@image_url} />
        <.image_text_content
          title={@title}
          description={@description}
          link_text={@link_text}
          link_page={@link_page}
          link_href={@link_href}
          mode={@mode}
        />
      <% else %>
        <.image_text_content
          title={@title}
          description={@description}
          link_text={@link_text}
          link_page={@link_page}
          link_href={@link_href}
          mode={@mode}
        />
        <.image_text_image image_url={@image_url} />
      <% end %>
    </section>
    """
  end

  attr :image_url, :string, required: true

  defp image_text_image(assigns) do
    ~H"""
    <div
      class="image-text-image"
      style={"background-image: url('#{@image_url}');"}
    >
    </div>
    """
  end

  attr :title, :string, required: true
  attr :description, :string, required: true
  attr :link_text, :string, default: nil
  attr :link_page, :string, default: nil
  attr :link_href, :string, default: nil
  attr :mode, :atom, required: true

  defp image_text_content(assigns) do
    ~H"""
    <div>
      <h2 class="t-heading">
        {@title}
      </h2>
      <p class="image-text-body">
        {@description}
      </p>
      <%= if @link_text do %>
        <%= if @mode == :preview do %>
          <a
            href="#"
            phx-click="change_preview_page"
            phx-value-page={@link_page}
            class="accent-link"
          >
            {@link_text}
          </a>
        <% else %>
          <.link
            patch={@link_href || "/"}
            class="accent-link"
          >
            {@link_text}
          </.link>
        <% end %>
      <% end %>
    </div>
    """
  end

  @doc """
  Renders a page header with title and optional product count.

  ## Attributes

  * `title` - Required. The page title.
  * `subtitle` - Optional. Text below the title.
  * `product_count` - Optional. Number to display as "X products".

  ## Examples

      <.collection_header title="All Products" product_count={24} />
  """
  attr :title, :string, required: true
  attr :subtitle, :string, default: nil
  attr :product_count, :integer, default: nil

  def collection_header(assigns) do
    ~H"""
    <div class="collection-header-wrap">
      <div class="collection-header-inner">
        <h1 class="t-heading">
          {@title}
        </h1>
        <%= if @subtitle do %>
          <p class="collection-header-meta">{@subtitle}</p>
        <% end %>
        <%= if @product_count do %>
          <p class="collection-header-meta">{@product_count} products</p>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders a filter bar with category pills and sort dropdown.

  ## Attributes

  * `categories` - Required. List of category maps with `name` field.
  * `active_category` - Optional. Currently selected category name. Defaults to "All".
  * `sort_options` - Optional. List of sort option strings.

  ## Examples

      <.filter_bar categories={@categories} />
      <.filter_bar categories={@categories} active_category="Art Prints" />
  """
  attr :categories, :list, required: true
  attr :active_category, :string, default: "All"

  attr :sort_options, :list,
    default: [
      "Sort by: Featured",
      "Price: Low to High",
      "Price: High to Low",
      "Newest",
      "Best Selling"
    ]

  def filter_bar(assigns) do
    ~H"""
    <div class="filter-bar">
      <!-- Category Pills -->
      <div class="filter-pills-container">
        <button class={"filter-pill#{if @active_category == "All", do: " filter-pill-active", else: ""}"}>
          All
        </button>
        <%= for category <- @categories do %>
          <button class={"filter-pill#{if @active_category == category.name, do: " filter-pill-active", else: ""}"}>
            {category.name}
          </button>
        <% end %>
      </div>
      
    <!-- Sort Dropdown -->
      <.shop_select options={@sort_options} />
    </div>
    """
  end

  @doc """
  Renders a breadcrumb navigation.

  ## Attributes

  * `items` - Required. List of breadcrumb items. Each item is a map with:
    - `label` - Required. Display text
    - `page` - Optional. Page name for preview mode navigation
    - `href` - Optional. URL for live mode navigation
    - `current` - Optional. Boolean, if true this is the current page (not a link)
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.breadcrumb items={[
        %{label: "Home", page: "home", href: "/"},
        %{label: "Art Prints", page: "collection", href: "/collections/art-prints"},
        %{label: "Mountain Sunrise", current: true}
      ]} mode={:preview} />
  """
  attr :items, :list, required: true
  attr :mode, :atom, default: :live

  def breadcrumb(assigns) do
    ~H"""
    <nav aria-label="Breadcrumb" class="breadcrumb">
      <ol>
        <%= for {item, _index} <- Enum.with_index(@items) do %>
          <%= if item[:current] do %>
            <li aria-current="page">{item.label}</li>
          <% else %>
            <li>
              <%= if @mode == :preview do %>
                <a
                  href="#"
                  phx-click="change_preview_page"
                  phx-value-page={item.page}
                >
                  {item.label}
                </a>
              <% else %>
                <.link patch={item.href || "/"}>{item.label}</.link>
              <% end %>
            </li>
          <% end %>
        <% end %>
      </ol>
    </nav>
    """
  end

  @doc """
  Renders a related products section with title and product grid.

  ## Attributes

  * `title` - Optional. Section heading. Defaults to "You might also like".
  * `products` - Required. List of products to display.
  * `theme_settings` - Required. The theme settings map.
  * `limit` - Optional. Maximum products to show. Defaults to 4.
  * `mode` - Either `:live` (default) or `:preview`.

  ## Examples

      <.related_products_section
        products={@related_products}
        theme_settings={@theme_settings}
        mode={:preview}
      />
  """
  attr :title, :string, default: "You might also like"
  attr :products, :list, required: true
  attr :theme_settings, :map, required: true
  attr :limit, :integer, default: 4
  attr :mode, :atom, default: :live

  def related_products_section(assigns) do
    ~H"""
    <div class="related-section">
      <h2 class="t-heading">
        {@title}
      </h2>

      <.product_grid columns={:fixed_4}>
        <%= for product <- Enum.take(@products, @limit) do %>
          <.product_card
            product={product}
            theme_settings={@theme_settings}
            mode={@mode}
            variant={:compact}
          />
        <% end %>
      </.product_grid>
    </div>
    """
  end

  @doc """
  Renders a product image gallery with thumbnails and lightbox.

  ## Attributes

  * `images` - Required. List of image URLs.
  * `product_name` - Required. Product name for alt text.
  * `id_prefix` - Optional. Prefix for element IDs. Defaults to "pdp".

  ## Examples

      <.product_gallery images={@product_images} product_name={@product.title} />
  """
  attr :images, :list, required: true
  attr :product_name, :string, required: true
  attr :id_prefix, :string, default: "pdp"

  def product_gallery(assigns) do
    ~H"""
    <div class="pdp-gallery">
      <%!-- Image area (relative container for dots + desktop nav) --%>
      <div class="pdp-gallery-frame">
        <%!-- Scroll-snap carousel (2+ images) or single image --%>
        <%= if length(@images) > 1 do %>
          <div
            id={"#{@id_prefix}-carousel"}
            class="pdp-gallery-carousel"
            phx-hook="ProductImageScroll"
            role="region"
            aria-label="Product images"
          >
            <img
              :for={{url, idx} <- Enum.with_index(@images)}
              src={url}
              alt={"#{@product_name} — image #{idx + 1} of #{length(@images)}"}
              class="pdp-carousel-img"
              width="600"
              height="600"
              loading={if idx == 0, do: nil, else: "lazy"}
              decoding={if idx == 0, do: nil, else: "async"}
            />
          </div>

          <%!-- Desktop: lightbox click area (transparent, above carousel) --%>
          <div
            class="pdp-lightbox-click"
            phx-click={Phoenix.LiveView.JS.exec("data-show", to: "##{@id_prefix}-lightbox")}
          />

          <%!-- Desktop: prev/next arrows (same chevrons as lightbox) --%>
          <button
            type="button"
            class="pdp-nav pdp-nav-prev"
            aria-label="Previous image"
            phx-click={Phoenix.LiveView.JS.dispatch("pdp:scroll-prev", to: "##{@id_prefix}-carousel")}
          >
            <svg
              width="24"
              height="24"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
            >
              <polyline points="15 18 9 12 15 6" />
            </svg>
          </button>
          <button
            type="button"
            class="pdp-nav pdp-nav-next"
            aria-label="Next image"
            phx-click={Phoenix.LiveView.JS.dispatch("pdp:scroll-next", to: "##{@id_prefix}-carousel")}
          >
            <svg
              width="24"
              height="24"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
            >
              <polyline points="9 18 15 12 9 6" />
            </svg>
          </button>
        <% else %>
          <div class="pdp-gallery-single">
            <%= if @images == [] do %>
              <div
                class="product-card-placeholder"
                role="img"
                aria-label={@product_name}
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  fill="none"
                  viewBox="0 0 24 24"
                  stroke-width="1.5"
                  stroke="currentColor"
                  width="48"
                  height="48"
                  class="placeholder-icon"
                >
                  <path
                    stroke-linecap="round"
                    stroke-linejoin="round"
                    d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909M3.75 21h16.5A2.25 2.25 0 0 0 22.5 18.75V5.25A2.25 2.25 0 0 0 20.25 3H3.75A2.25 2.25 0 0 0 1.5 5.25v13.5A2.25 2.25 0 0 0 3.75 21Zm16.5-13.5a1.125 1.125 0 1 1-2.25 0 1.125 1.125 0 0 1 2.25 0Z"
                  />
                </svg>
              </div>
            <% else %>
              <img
                src={List.first(@images)}
                alt={@product_name}
                width="600"
                height="600"
              />
              <div
                class="pdp-lightbox-click"
                phx-click={Phoenix.LiveView.JS.exec("data-show", to: "##{@id_prefix}-lightbox")}
              />
            <% end %>
          </div>
        <% end %>

        <%!-- Dot indicators (absolute over image, hidden on desktop) --%>
        <div
          :if={length(@images) > 1}
          class="product-image-dots"
          aria-hidden="true"
        >
          <span
            :for={{_, idx} <- Enum.with_index(@images)}
            class={["product-image-dot", idx == 0 && "product-image-dot-active"]}
          />
        </div>
      </div>

      <%!-- Desktop: thumbnail grid --%>
      <div :if={length(@images) > 1} class="pdp-gallery-thumbs">
        <%= for {url, idx} <- Enum.with_index(@images) do %>
          <button
            type="button"
            class={"pdp-thumbnail#{if idx == 0, do: " pdp-thumbnail-active", else: ""}"}
            aria-label={"View image #{idx + 1} of #{length(@images)}"}
            phx-click={
              Phoenix.LiveView.JS.dispatch("pdp:scroll-to",
                detail: %{index: idx},
                to: "##{@id_prefix}-carousel"
              )
              |> Phoenix.LiveView.JS.set_attribute(
                {"data-current-index", to_string(idx)},
                to: "##{@id_prefix}-lightbox"
              )
              |> Phoenix.LiveView.JS.remove_class("pdp-thumbnail-active",
                to: ".pdp-thumbnail"
              )
              |> Phoenix.LiveView.JS.add_class("pdp-thumbnail-active")
            }
          >
            <img
              src={url}
              alt=""
              width="150"
              height="150"
              loading="lazy"
            />
          </button>
        <% end %>
      </div>

      <.product_lightbox
        :if={@images != []}
        images={@images}
        product_name={@product_name}
        id_prefix={@id_prefix}
      />
    </div>
    """
  end

  # Private: Renders a product image lightbox dialog used by `product_gallery`.
  attr :images, :list, required: true
  attr :product_name, :string, required: true
  attr :id_prefix, :string, required: true

  defp product_lightbox(assigns) do
    ~H"""
    <dialog
      class="lightbox"
      id={"#{@id_prefix}-lightbox"}
      aria-label="Product image gallery"
      data-current-index="0"
      data-images={Jason.encode!(@images)}
      data-show={Phoenix.LiveView.JS.exec("phx-show-lightbox", to: "##{@id_prefix}-lightbox")}
      phx-show-lightbox={
        Phoenix.LiveView.JS.dispatch("pdp:open-lightbox", to: "##{@id_prefix}-lightbox")
      }
      phx-hook="Lightbox"
    >
      <div class="lightbox-content">
        <button
          type="button"
          class="lightbox-close"
          aria-label="Close gallery"
          phx-click={
            Phoenix.LiveView.JS.dispatch("pdp:close-lightbox", to: "##{@id_prefix}-lightbox")
          }
        >
          <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
          >
            <line x1="18" y1="6" x2="6" y2="18"></line>
            <line x1="6" y1="6" x2="18" y2="18"></line>
          </svg>
        </button>
        <button
          type="button"
          class="lightbox-nav lightbox-prev"
          aria-label="Previous image"
          phx-click={Phoenix.LiveView.JS.dispatch("pdp:prev-image", to: "##{@id_prefix}-lightbox")}
        >
          <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
          >
            <polyline points="15 18 9 12 15 6"></polyline>
          </svg>
        </button>
        <figure class="lightbox-figure">
          <div class="lightbox-image-container">
            <img
              class="lightbox-image"
              src={List.first(@images)}
              alt={@product_name}
              width="1200"
              height="1200"
            />
          </div>
          <figcaption class="lightbox-caption">{@product_name}</figcaption>
        </figure>
        <button
          type="button"
          class="lightbox-nav lightbox-next"
          aria-label="Next image"
          phx-click={Phoenix.LiveView.JS.dispatch("pdp:next-image", to: "##{@id_prefix}-lightbox")}
        >
          <svg
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
          >
            <polyline points="9 18 15 12 9 6"></polyline>
          </svg>
        </button>
        <div class="lightbox-counter">1 / {length(@images)}</div>
      </div>
    </dialog>
    """
  end

  @doc """
  Renders product title and price information.

  ## Attributes

  * `product` - Required. Product struct with `title`, `cheapest_price`, `on_sale`, `compare_at_price`.
  * `display_price` - Optional. Override price to display (e.g. selected variant price).

  ## Examples

      <.product_info product={@product} />
      <.product_info product={@product} display_price={@display_price} />
  """
  attr :product, :map, required: true
  attr :display_price, :integer, default: nil

  def product_info(assigns) do
    assigns = assign(assigns, :price, assigns.display_price || assigns.product.cheapest_price)

    ~H"""
    <div>
      <h1 class="t-heading pdp-title">
        {@product.title}
      </h1>

      <div class="pdp-price-row">
        <%= if @product.on_sale do %>
          <span class="product-price--sale">
            {Berrypod.Cart.format_price(@price)}
          </span>
          <span class="product-price--compare">
            {Berrypod.Cart.format_price(@product.compare_at_price)}
          </span>
          <span class="sale-badge">
            SAVE {round((@product.compare_at_price - @price) / @product.compare_at_price * 100)}%
          </span>
        <% else %>
          <span class="product-price--regular">
            {Berrypod.Cart.format_price(@price)}
          </span>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders a variant selector for a single option type.

  Shows color swatches for color-type options, text buttons for others.
  In shop mode, each option is a patch link for progressive enhancement.
  In preview mode, options are inert buttons.

  ## Attributes

  * `option_type` - Required. Map with :name, :type, :values keys
  * `selected` - Required. Currently selected value (string)
  * `available` - Required. List of available values for this option
  * `option_urls` - Optional. Map of value title => patch URL
  * `mode` - Optional. :shop or :preview (default: :shop)

  ## Examples

      <.variant_selector
        option_type={%{name: "Size", type: :size, values: [%{title: "S"}, ...]}}
        selected="M"
        available={["S", "M", "L"]}
        option_urls={%{"S" => "/products/foo?Size=S", ...}}
      />
  """
  attr :option_type, :map, required: true
  attr :selected, :string, required: true
  attr :available, :list, required: true
  attr :option_urls, :map, default: %{}
  attr :mode, :atom, default: :shop

  def variant_selector(assigns) do
    ~H"""
    <div class="variant-selector">
      <div class="variant-label">
        {@option_type.name}<span
          :if={@selected}
          class="variant-label-value"
        >: {@selected}</span>
      </div>
      <div class="variant-options">
        <%= if @option_type.type == :color do %>
          <.color_swatch
            :for={value <- @option_type.values}
            title={value.title}
            hex={value[:hex] || "#888888"}
            selected={value.title == @selected}
            disabled={value.title not in @available}
            mode={@mode}
            url={@option_urls[value.title]}
          />
        <% else %>
          <.size_button
            :for={value <- @option_type.values}
            title={value.title}
            selected={value.title == @selected}
            disabled={value.title not in @available}
            mode={@mode}
            url={@option_urls[value.title]}
          />
        <% end %>
      </div>
    </div>
    """
  end

  attr :title, :string, required: true
  attr :hex, :string, required: true
  attr :selected, :boolean, required: true
  attr :disabled, :boolean, required: true
  attr :mode, :atom, default: :shop
  attr :url, :string, default: nil

  defp color_swatch(assigns) do
    ~H"""
    <%= cond do %>
      <% @mode == :shop and not @disabled -> %>
        <.link
          patch={@url}
          class="color-swatch"
          style={"background-color: #{@hex};"}
          title={@title}
          aria-label={"Select #{@title}"}
          aria-pressed={to_string(@selected)}
        >
        </.link>
      <% @mode == :shop -> %>
        <span
          class="color-swatch"
          style={"background-color: #{@hex};"}
          title={"#{@title} (unavailable)"}
          aria-label={"#{@title} (unavailable)"}
          aria-disabled="true"
        />
      <% true -> %>
        <button
          type="button"
          class="color-swatch"
          style={"background-color: #{@hex};"}
          title={@title}
          aria-label={"Select #{@title}"}
          aria-pressed={to_string(@selected)}
        />
    <% end %>
    """
  end

  attr :title, :string, required: true
  attr :selected, :boolean, required: true
  attr :disabled, :boolean, required: true
  attr :mode, :atom, default: :shop
  attr :url, :string, default: nil

  defp size_button(assigns) do
    ~H"""
    <%= cond do %>
      <% @mode == :shop and not @disabled -> %>
        <.link
          patch={@url}
          class="size-btn"
          aria-pressed={to_string(@selected)}
        >
          {@title}
        </.link>
      <% @mode == :shop -> %>
        <span
          class="size-btn"
          aria-disabled="true"
        >
          {@title}
        </span>
      <% true -> %>
        <button
          type="button"
          class="size-btn"
          aria-pressed={to_string(@selected)}
        >
          {@title}
        </button>
    <% end %>
    """
  end

  @doc """
  Renders a quantity selector with increment/decrement buttons.

  ## Attributes

  * `quantity` - Optional. Current quantity value. Defaults to 1.
  * `in_stock` - Optional. Whether the product is in stock. Defaults to true.
  * `min` - Optional. Minimum quantity. Defaults to 1.
  * `max` - Optional. Maximum quantity. Defaults to 99.

  ## Examples

      <.quantity_selector />
      <.quantity_selector quantity={2} in_stock={false} />
  """
  attr :quantity, :integer, default: 1
  attr :in_stock, :boolean, default: true
  attr :min, :integer, default: 1
  attr :max, :integer, default: 99

  def quantity_selector(assigns) do
    ~H"""
    <div class="quantity-selector">
      <label class="qty-label">
        Quantity
      </label>
      <div class="qty-row">
        <div class="qty-group">
          <button
            type="button"
            phx-click="decrement_quantity"
            disabled={@quantity <= @min}
            aria-label="Decrease quantity"
            class="qty-btn"
          >
            −
          </button>
          <input
            type="number"
            name="quantity"
            value={@quantity}
            min={@min}
            max={@max}
            class="qty-display"
            aria-label="Quantity"
          />
          <button
            type="button"
            phx-click="increment_quantity"
            disabled={@quantity >= @max}
            aria-label="Increase quantity"
            class="qty-btn"
          >
            +
          </button>
        </div>
        <%= if @in_stock do %>
          <span class="stock-in">In stock</span>
        <% else %>
          <span class="stock-out">Out of stock</span>
        <% end %>
      </div>
    </div>
    """
  end

  @doc """
  Renders the add to cart button.

  ## Attributes

  * `text` - Optional. Button text. Defaults to "Add to basket".
  * `disabled` - Optional. Whether button is disabled. Defaults to false.
  * `sticky` - Optional. Whether to use sticky positioning on mobile. Defaults to true.
  * `mode` - Either `:live` (sends add_to_cart event) or `:preview` (opens drawer only).

  ## Examples

      <.add_to_cart_button />
      <.add_to_cart_button text="Add to bag" disabled={true} />
  """
  attr :text, :string, default: "Add to basket"
  attr :disabled, :boolean, default: false
  attr :sticky, :boolean, default: true
  attr :mode, :atom, default: :live

  def add_to_cart_button(assigns) do
    ~H"""
    <div class="atc-wrap" data-sticky={to_string(@sticky)}>
      <button
        type={if @mode == :preview, do: "button", else: "submit"}
        phx-click={if @mode == :preview, do: open_cart_drawer_js()}
        disabled={@disabled}
        class="atc-btn"
      >
        {@text}
      </button>
    </div>
    """
  end

  defp open_cart_drawer_js do
    Phoenix.LiveView.JS.push("open_cart_drawer")
  end

  @doc """
  Renders a collapsible details/accordion item.

  ## Attributes

  * `title` - Required. Section heading text.
  * `open` - Optional. Whether section is expanded by default. Defaults to false.

  ## Slots

  * `inner_block` - Required. Content to show when expanded.

  ## Examples

      <.accordion_item title="Description" open={true}>
        <p>Product description here...</p>
      </.accordion_item>
  """
  attr :title, :string, required: true
  attr :open, :boolean, default: false

  slot :inner_block, required: true

  def accordion_item(assigns) do
    ~H"""
    <details open={@open}>
      <summary class="accordion-summary">
        <span class="accordion-title">{@title}</span>
        <svg
          class="accordion-icon"
          width="20"
          height="20"
          fill="none"
          stroke="currentColor"
          viewBox="0 0 24 24"
        >
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
        </svg>
      </summary>
      <div class="accordion-body">
        {render_slot(@inner_block)}
      </div>
    </details>
    """
  end

  @doc """
  Renders a product details accordion with Description, Size Guide, and Shipping sections.

  ## Attributes

  * `product` - Required. Product map with `description`.
  * `show_size_guide` - Optional. Whether to show size guide. Defaults to true.
  * `size_guide` - Optional. Custom size guide data. Uses default if not provided.

  ## Examples

      <.product_details product={@product} />
      <.product_details product={@product} show_size_guide={false} />
  """
  attr :product, :map, required: true
  attr :show_size_guide, :boolean, default: true
  attr :size_guide, :list, default: nil

  def product_details(assigns) do
    assigns =
      assign_new(assigns, :sizes, fn ->
        assigns.size_guide ||
          [
            %{size: "S", chest: "86-91", length: "71"},
            %{size: "M", chest: "91-96", length: "73"},
            %{size: "L", chest: "96-101", length: "75"},
            %{size: "XL", chest: "101-106", length: "77"}
          ]
      end)

    ~H"""
    <div class="details-wrap">
      <.accordion_item title="Description" open={true}>
        <p class="details-description">
          {@product.description}. Crafted with attention to detail and quality materials, this product is designed to last. Perfect for everyday use or special occasions.
        </p>
      </.accordion_item>

      <%= if @show_size_guide do %>
        <.accordion_item title="Size Guide">
          <table class="details-table">
            <thead>
              <tr class="details-table-row">
                <th class="details-th">
                  Size
                </th>
                <th class="details-th">
                  Chest (cm)
                </th>
                <th class="details-th">
                  Length (cm)
                </th>
              </tr>
            </thead>
            <tbody>
              <%= for {size_row, idx} <- Enum.with_index(@sizes) do %>
                <tr class={idx < length(@sizes) - 1 && "details-table-row"}>
                  <td class="details-td">{size_row.size}</td>
                  <td class="details-td">{size_row.chest}</td>
                  <td class="details-td">{size_row.length}</td>
                </tr>
              <% end %>
            </tbody>
          </table>
        </.accordion_item>
      <% end %>

      <.accordion_item title="Shipping & Returns">
        <div class="details-shipping">
          <div>
            <p class="details-subheading">Delivery</p>
            <p class="details-shipping-text">
              Free UK delivery on orders over £40. Standard delivery 3-5 working days. Express delivery available at checkout.
            </p>
          </div>
          <div>
            <p class="details-subheading">Returns</p>
            <p class="details-shipping-text">
              We offer a 30-day return policy. Items must be unused and in original packaging. Please contact us to arrange a return.
            </p>
          </div>
        </div>
      </.accordion_item>
    </div>
    """
  end

  # ── Shop pagination ────────────────────────────────────────────

  @doc """
  Renders pagination controls for the shop collection page.

  Uses URL navigation (`<.link navigate=...>`) so pages are bookmarkable.

  ## Attributes

    * `page` - Required. A `%Berrypod.Pagination{}` struct.
    * `base_path` - Required. The base URL path (e.g. "/collections/all").
    * `params` - Extra query params to preserve (e.g. %{"sort" => "newest"}).
  """
  attr :page, Berrypod.Pagination, required: true
  attr :base_path, :string, required: true
  attr :params, :map, default: %{}

  def shop_pagination(assigns) do
    assigns =
      assigns
      |> assign(:showing, Berrypod.Pagination.showing_text(assigns.page))
      |> assign(:numbers, Berrypod.Pagination.page_numbers(assigns.page))

    ~H"""
    <nav
      :if={@page.total_pages > 1}
      aria-label="Pagination"
      class="shop-pagination"
    >
      <p class="shop-pagination-showing">{@showing}</p>

      <div class="shop-pagination-buttons">
        <.link
          :if={@page.page > 1}
          patch={pagination_url(@base_path, @page.page - 1, @params)}
          class="shop-pagination-btn"
          aria-label="Previous page"
        >
          &lsaquo; Prev
        </.link>

        <%= for item <- @numbers do %>
          <%= case item do %>
            <% :ellipsis -> %>
              <span class="shop-pagination-ellipsis" aria-hidden="true">&hellip;</span>
            <% n -> %>
              <.link
                patch={pagination_url(@base_path, n, @params)}
                aria-label={"Page #{n}"}
                aria-current={n == @page.page && "page"}
                class={["shop-pagination-btn", n == @page.page && "shop-pagination-btn-active"]}
              >
                {n}
              </.link>
          <% end %>
        <% end %>

        <.link
          :if={@page.page < @page.total_pages}
          patch={pagination_url(@base_path, @page.page + 1, @params)}
          class="shop-pagination-btn"
          aria-label="Next page"
        >
          Next &rsaquo;
        </.link>
      </div>
    </nav>
    """
  end

  defp pagination_url(base_path, page, params) do
    query = if page > 1, do: Map.put(params, "page", to_string(page)), else: params

    if query == %{} do
      base_path
    else
      base_path <> "?" <> URI.encode_query(query)
    end
  end
end
