defmodule SimpleshopThemeWeb.ShopComponents.Product do
  use Phoenix.Component

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

  alias SimpleshopTheme.Products.{Product, ProductImage}

  @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={card_classes(@variant)}
      style={card_style(@variant) <> if(@clickable_resolved, do: " position: relative;", else: "")}
    >
      <.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)

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

    ~H"""
    <div class={image_container_classes(@variant)} style="z-index: 1;">
      <%= 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 w-full h-full object-cover transition-opacity duration-300"
          />
          <.product_card_image
            image={@hover_image}
            alt={@product.title}
            variant={@variant}
            class="product-image-hover w-full h-full object-cover"
          />
        </div>
      <% else %>
        <.product_card_image
          image={@primary_image}
          alt={@product.title}
          variant={@variant}
          priority={@priority}
          class="product-image-primary w-full h-full object-cover"
        />
      <% 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 %>
    </div>
    <div class={content_padding_class(@variant)}>
      <%= if @show_category && Map.get(@product, :category) do %>
        <%= if @mode == :preview do %>
          <p
            class="text-xs mb-1"
            style="color: var(--t-text-tertiary); position: relative; z-index: 1;"
          >
            {@product.category}
          </p>
        <% else %>
          <.link
            navigate={"/collections/#{Slug.slugify(@product.category)}"}
            class="text-xs mb-1 block hover:underline"
            style="color: var(--t-text-tertiary); text-decoration: none; position: relative; z-index: 1;"
          >
            {@product.category}
          </.link>
        <% end %>
      <% end %>
      <h3 class={title_classes(@variant)} style={title_style(@variant)}>
        <%= if @clickable do %>
          <%= if @mode == :preview do %>
            <a
              href="#"
              phx-click="change_preview_page"
              phx-value-page="pdp"
              class="stretched-link"
              style="color: inherit; text-decoration: none;"
            >
              {@product.title}
            </a>
          <% else %>
            <.link
              navigate={"/products/#{Map.get(@product, :slug) || Map.get(@product, :id)}"}
              class="stretched-link"
              style="color: inherit; text-decoration: none;"
            >
              {@product.title}
            </.link>
          <% end %>
        <% else %>
          {@product.title}
        <% end %>
      </h3>
      <%= if @theme_settings.show_prices do %>
        <.product_price product={@product} variant={@variant} />
      <% end %>
      <%= if @show_delivery_text do %>
        <p class="text-xs mt-1" style="color: var(--t-text-tertiary);">
          Made to order
        </p>
      <% end %>
    </div>
    """
  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) ->
          {"/images/#{image.image_id}/variant/", 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, "flex items-center justify-center"]}
          style="color: var(--t-text-tertiary);"
          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="size-12 opacity-40"
          >
            <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, :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="text-lg font-bold"
              style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
            >
              {SimpleshopTheme.Cart.format_price(@product.cheapest_price)}
            </span>
            <span class="text-sm line-through ml-2" style="color: var(--t-text-tertiary);">
              {SimpleshopTheme.Cart.format_price(@product.compare_at_price)}
            </span>
          <% else %>
            <span class="text-lg font-bold" style="color: var(--t-text-primary);">
              {SimpleshopTheme.Cart.format_price(@product.cheapest_price)}
            </span>
          <% end %>
        </div>
      <% :featured -> %>
        <p class="text-sm" style="color: var(--t-text-secondary);">
          <%= if @product.on_sale do %>
            <span class="line-through mr-1" style="color: var(--t-text-tertiary);">
              {SimpleshopTheme.Cart.format_price(@product.compare_at_price)}
            </span>
          <% end %>
          {SimpleshopTheme.Cart.format_price(@product.cheapest_price)}
        </p>
      <% :compact -> %>
        <p class="font-bold" style="color: var(--t-text-primary);">
          {SimpleshopTheme.Cart.format_price(@product.cheapest_price)}
        </p>
      <% :minimal -> %>
        <p class="text-xs" style="color: var(--t-text-secondary);">
          {SimpleshopTheme.Cart.format_price(@product.cheapest_price)}
        </p>
    <% end %>
    """
  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}

  defp card_classes(:default), do: "product-card group overflow-hidden transition-all"

  defp card_classes(:featured),
    do: "product-card group overflow-hidden transition-all hover:-translate-y-1"

  defp card_classes(:compact), do: "product-card group overflow-hidden cursor-pointer"
  defp card_classes(:minimal), do: "product-card group overflow-hidden"

  defp card_style(:default),
    do:
      "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card); cursor: pointer;"

  defp card_style(:featured),
    do:
      "background-color: var(--t-surface-raised); border-radius: var(--t-radius-card); cursor: pointer;"

  defp card_style(:compact),
    do:
      "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card);"

  defp card_style(:minimal),
    do:
      "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-subtle); border-radius: var(--t-radius-card);"

  defp image_container_classes(:compact),
    do: "product-image-container aspect-square bg-gray-200 overflow-hidden relative"

  defp image_container_classes(:minimal),
    do: "product-image-container aspect-square bg-gray-200 overflow-hidden relative"

  defp image_container_classes(_),
    do: "product-image-container bg-gray-200 overflow-hidden relative"

  defp content_padding_class(:compact), do: "p-3"
  defp content_padding_class(:minimal), do: "p-2"
  defp content_padding_class(_), do: ""

  defp title_classes(:default), do: "font-semibold mb-2"
  defp title_classes(:featured), do: "text-sm font-medium mb-1"
  defp title_classes(:compact), do: "font-semibold text-sm mb-1"
  defp title_classes(:minimal), do: "text-xs font-semibold truncate"

  defp title_style(:default),
    do: "font-family: var(--t-font-heading); color: var(--t-text-primary);"

  defp title_style(:featured), do: "color: var(--t-text-primary);"

  defp title_style(:compact),
    do: "font-family: var(--t-font-heading); color: var(--t-text-primary);"

  defp title_style(:minimal), do: "color: var(--t-text-primary);"

  @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} gap="gap-6">
        ...
      </.product_grid>
  """
  attr :theme_settings, :map, default: nil
  attr :columns, :atom, default: nil
  attr :gap, :string, default: nil
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def product_grid(assigns) do
    ~H"""
    <div class={grid_classes(@theme_settings, @columns, @gap, @class)}>
      {render_slot(@inner_block)}
    </div>
    """
  end

  defp grid_classes(theme_settings, columns, gap, extra_class) do
    base = "product-grid grid"

    cols =
      cond do
        columns == :fixed_4 ->
          "grid-cols-2 md:grid-cols-4"

        theme_settings != nil ->
          responsive_cols = "grid-cols-1 sm:grid-cols-2"

          lg_cols =
            case theme_settings.grid_columns do
              "2" -> "lg:grid-cols-2"
              "3" -> "lg:grid-cols-3"
              "4" -> "lg:grid-cols-4"
              _ -> "lg:grid-cols-3"
            end

          "#{responsive_cols} #{lg_cols}"

        true ->
          "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
      end

    gap_class = gap || ""

    [base, cols, gap_class, extra_class]
    |> Enum.reject(&(is_nil(&1) or &1 == ""))
    |> Enum.join(" ")
  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="text-center"
          style={"padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-#{@background});"}
        >
          <h1
            class="text-3xl md:text-4xl mb-4"
            style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
          >
            {@title}
          </h1>
          <p
            class="text-lg max-w-lg mx-auto mb-8"
            style="color: var(--t-text-secondary); line-height: 1.6;"
          >
            {@description}
          </p>
          <.hero_cta
            :if={@cta_text}
            text={@cta_text}
            page={@cta_page}
            href={@cta_href}
            mode={@mode}
            variant={:primary}
          />
        </section>
      <% :page -> %>
        <div class="text-center" style="padding-top: var(--space-2xl);">
          <h1
            class="text-4xl md:text-5xl font-bold mb-6"
            style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
          >
            {@title}
          </h1>
          <p class="text-lg mb-12 max-w-2xl mx-auto" style="color: var(--t-text-secondary);">
            {@description}
          </p>
        </div>
      <% :error -> %>
        <div class="text-center">
          <%= if @pre_title do %>
            <h1
              class="text-8xl md:text-9xl font-bold mb-4"
              style="font-family: var(--t-font-heading); color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); font-weight: var(--t-heading-weight);"
            >
              {@pre_title}
            </h1>
          <% end %>
          <h2
            class="text-3xl md:text-4xl font-bold mb-6"
            style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
          >
            {@title}
          </h2>
          <p class="text-lg mb-8 max-w-md mx-auto" style="color: var(--t-text-secondary);">
            {@description}
          </p>
          <%= if @cta_text || @secondary_cta_text do %>
            <div class="flex flex-col sm:flex-row gap-4 justify-center">
              <.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
    ~H"""
    <%= if @mode == :preview do %>
      <button
        phx-click="change_preview_page"
        phx-value-page={@page}
        class={hero_cta_classes(@variant)}
        style={hero_cta_style(@variant)}
      >
        {@text}
      </button>
    <% else %>
      <.link
        navigate={@href || "/"}
        class={["inline-block", hero_cta_classes(@variant)]}
        style={hero_cta_style(@variant) <> " text-decoration: none;"}
      >
        {@text}
      </.link>
    <% end %>
    """
  end

  defp hero_cta_classes(:primary), do: "themed-button px-8 py-3 font-semibold transition-all"

  defp hero_cta_classes(:secondary),
    do: "themed-button-outline px-8 py-3 font-semibold transition-all"

  defp hero_cta_style(:primary), do: ""
  defp hero_cta_style(:secondary), do: ""

  @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 style="padding: var(--space-xl) var(--space-lg); background-color: var(--t-surface-base);">
      <h2 class="sr-only">Shop by Category</h2>
      <nav class="grid grid-cols-3 gap-4 max-w-3xl mx-auto" 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="flex flex-col items-center gap-3 p-4 rounded-lg transition-colors hover:bg-black/5"
              style="text-decoration: none; cursor: pointer;"
            >
              <div
                class="w-24 h-24 rounded-full bg-gray-200 bg-cover bg-center transition-transform hover:scale-105"
                style={
                  if(category[:image_url],
                    do: "background-image: url('#{category.image_url}');",
                    else: ""
                  )
                }
              >
              </div>
              <span
                class="text-sm font-medium"
                style="font-family: var(--t-font-body); color: var(--t-text-primary);"
              >
                {category.name}
              </span>
            </a>
          <% else %>
            <.link
              navigate={"/collections/#{category.slug}"}
              class="flex flex-col items-center gap-3 p-4 rounded-lg transition-colors hover:bg-black/5"
              style="text-decoration: none;"
            >
              <div
                class="w-24 h-24 rounded-full bg-gray-200 bg-cover bg-center transition-transform hover:scale-105"
                style={
                  if(category[:image_url],
                    do: "background-image: url('#{category.image_url}');",
                    else: ""
                  )
                }
              >
              </div>
              <span
                class="text-sm font-medium"
                style="font-family: var(--t-font-body); color: var(--t-text-primary);"
              >
                {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 style="padding: var(--space-xl) var(--space-lg); background-color: var(--t-surface-sunken);">
      <h2
        class="text-2xl mb-6"
        style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
      >
        {@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="text-center mt-8">
        <%= if @mode == :preview do %>
          <button
            phx-click="change_preview_page"
            phx-value-page={@cta_page}
            class="px-6 py-3 font-medium transition-all"
            style="background-color: transparent; color: var(--t-text-primary); border: 1px solid var(--t-text-primary); border-radius: var(--t-radius-button); cursor: pointer;"
          >
            {@cta_text}
          </button>
        <% else %>
          <.link
            navigate={@cta_href}
            class="inline-block px-6 py-3 font-medium transition-all"
            style="background-color: transparent; color: var(--t-text-primary); border: 1px solid var(--t-text-primary); border-radius: var(--t-radius-button); text-decoration: none;"
          >
            {@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="grid grid-cols-1 md:grid-cols-2 gap-12 items-center"
      style="padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-base);"
    >
      <%= 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="h-72 rounded-lg bg-cover bg-center"
      style={"background-image: url('#{@image_url}'); border-radius: var(--t-radius-image);"}
    >
    </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="text-2xl mb-4"
        style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
      >
        {@title}
      </h2>
      <p class="text-base mb-4" style="color: var(--t-text-secondary); line-height: 1.7;">
        {@description}
      </p>
      <%= if @link_text do %>
        <%= if @mode == :preview do %>
          <a
            href="#"
            phx-click="change_preview_page"
            phx-value-page={@link_page}
            class="text-sm font-medium transition-colors"
            style="color: var(--t-accent-text, hsl(var(--t-accent-h) var(--t-accent-s) 38%)); text-decoration: none; cursor: pointer;"
          >
            {@link_text}
          </a>
        <% else %>
          <.link
            navigate={@link_href || "/"}
            class="text-sm font-medium transition-colors"
            style="color: var(--t-accent-text, hsl(var(--t-accent-h) var(--t-accent-s) 38%)); text-decoration: none;"
          >
            {@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="border-b"
      style="background-color: var(--t-surface-raised); border-color: var(--t-border-default);"
    >
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        <h1
          class="text-3xl md:text-4xl font-bold mb-2"
          style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
        >
          {@title}
        </h1>
        <%= if @subtitle do %>
          <p style="color: var(--t-text-secondary);">{@subtitle}</p>
        <% end %>
        <%= if @product_count do %>
          <p style="color: var(--t-text-secondary);">{@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="flex flex-wrap items-center justify-between gap-4 mb-6">
      <!-- Category Pills -->
      <div class="filter-pills-container flex gap-2 overflow-x-auto">
        <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} class="px-4 py-2" />
    </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" style="color: var(--t-text-secondary);">
      <ol>
        <%= for {item, _index} <- Enum.with_index(@items) do %>
          <%= if item[:current] do %>
            <li aria-current="page" style="color: var(--t-text-primary);">{item.label}</li>
          <% else %>
            <li>
              <%= if @mode == :preview do %>
                <a
                  href="#"
                  phx-click="change_preview_page"
                  phx-value-page={item.page}
                  class="hover:underline"
                >
                  {item.label}
                </a>
              <% else %>
                <.link navigate={item.href || "/"} class="hover:underline">{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="py-12" style="border-top: 1px solid var(--t-border-default);">
      <h2
        class="text-2xl font-bold mb-6"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);"
      >
        {@title}
      </h2>

      <.product_grid columns={:fixed_4} gap="gap-6">
        <%= 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="relative" style="border-radius: var(--t-radius-image); overflow: hidden;">
        <%!-- 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="w-full h-full flex items-center justify-center"
                style="color: var(--t-text-tertiary);"
                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="size-12 opacity-40"
                >
                  <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"
                class="w-full h-full object-cover"
              />
              <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={"aspect-square bg-gray-200 overflow-hidden pdp-thumbnail#{if idx == 0, do: " pdp-thumbnail-active", else: ""}"}
            style="border-radius: var(--t-radius-image);"
            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"
              class="w-full h-full object-cover"
            />
          </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"
              id="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" id="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="text-3xl md:text-4xl font-bold mb-4"
        style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking);"
      >
        {@product.title}
      </h1>

      <div class="flex items-center gap-4 mb-6">
        <%= if @product.on_sale do %>
          <span
            class="text-3xl font-bold"
            style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"
          >
            {SimpleshopTheme.Cart.format_price(@price)}
          </span>
          <span class="text-xl line-through" style="color: var(--t-text-tertiary);">
            {SimpleshopTheme.Cart.format_price(@product.compare_at_price)}
          </span>
          <span
            class="px-2 py-1 text-sm font-bold text-white rounded"
            style="background-color: var(--t-sale-color);"
          >
            SAVE {round((@product.compare_at_price - @price) / @product.compare_at_price * 100)}%
          </span>
        <% else %>
          <span class="text-3xl font-bold" style="color: var(--t-text-primary);">
            {SimpleshopTheme.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.
  Disables unavailable options and fires `select_option` event on click.

  ## 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
  * `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"]}
      />
  """
  attr :option_type, :map, required: true
  attr :selected, :string, required: true
  attr :available, :list, required: true
  attr :mode, :atom, default: :shop

  def variant_selector(assigns) do
    ~H"""
    <div class="mb-6">
      <label class="block font-semibold mb-2" style="color: var(--t-text-primary);">
        {@option_type.name}
      </label>
      <div class="flex flex-wrap gap-2">
        <%= 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}
            option_name={@option_type.name}
            mode={@mode}
          />
        <% else %>
          <.size_button
            :for={value <- @option_type.values}
            title={value.title}
            selected={value.title == @selected}
            disabled={value.title not in @available}
            option_name={@option_type.name}
            mode={@mode}
          />
        <% 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 :option_name, :string, required: true
  attr :mode, :atom, default: :shop

  defp color_swatch(assigns) do
    ~H"""
    <button
      type="button"
      phx-click={if @mode == :shop and not @disabled, do: "select_option"}
      phx-value-option={@option_name}
      phx-value-value={@title}
      class={[
        "w-10 h-10 rounded-full border-2 transition-all relative",
        @selected && "ring-2 ring-offset-2",
        @disabled && "opacity-40 cursor-not-allowed"
      ]}
      style={"background-color: #{@hex}; border-color: #{if @selected, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l))", else: "var(--t-border-default)"}; --tw-ring-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"}
      title={@title}
      disabled={@disabled}
      aria-label={"Select #{@title}"}
      aria-pressed={@selected}
    >
      <span :if={@disabled} class="absolute inset-0 flex items-center justify-center">
        <span class="w-full h-0.5 bg-gray-400 rotate-45 absolute"></span>
      </span>
    </button>
    """
  end

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

  defp size_button(assigns) do
    ~H"""
    <button
      type="button"
      phx-click={if @mode == :shop and not @disabled, do: "select_option"}
      phx-value-option={@option_name}
      phx-value-value={@title}
      class={[
        "px-4 py-2 font-medium transition-all",
        @disabled && "opacity-40 cursor-not-allowed line-through"
      ]}
      style={"border: 2px solid #{if @selected, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l))", else: "var(--t-border-default)"}; border-radius: var(--t-radius-button); color: var(--t-text-primary); background: #{if @selected, do: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.1)", else: "transparent"};"}
      disabled={@disabled}
      aria-pressed={@selected}
    >
      {@title}
    </button>
    """
  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="mb-8">
      <label class="block font-semibold mb-2" style="color: var(--t-text-primary);">
        Quantity
      </label>
      <div class="flex items-center gap-4">
        <div
          class="flex items-center"
          style="border: 2px solid var(--t-border-default); border-radius: var(--t-radius-input);"
        >
          <button
            type="button"
            phx-click="decrement_quantity"
            disabled={@quantity <= @min}
            aria-label="Decrease quantity"
            class="px-4 py-2 disabled:opacity-30"
            style="color: var(--t-text-primary);"
          >
            −
          </button>
          <span
            class="px-4 py-2 border-x-2 min-w-12 text-center tabular-nums"
            style="border-color: var(--t-border-default); color: var(--t-text-primary);"
          >
            {@quantity}
          </span>
          <button
            type="button"
            phx-click="increment_quantity"
            disabled={@quantity >= @max}
            aria-label="Increase quantity"
            class="px-4 py-2 disabled:opacity-30"
            style="color: var(--t-text-primary);"
          >
            +
          </button>
        </div>
        <%= if @in_stock do %>
          <span class="text-sm" style="color: var(--t-text-tertiary);">In stock</span>
        <% else %>
          <span class="text-sm font-semibold" style="color: var(--t-sale-color);">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={[
        "mb-4",
        @sticky &&
          "sticky bottom-0 z-10 py-3 md:relative md:py-0 -mx-4 px-4 md:mx-0 md:px-0 border-t md:border-0"
      ]}
      style="background-color: var(--t-surface-base); border-color: var(--t-border-subtle);"
    >
      <button
        type="button"
        phx-click={if @mode == :preview, do: open_cart_drawer_js(), else: "add_to_cart"}
        disabled={@disabled}
        class="w-full px-6 py-4 text-lg font-semibold transition-all"
        style={"background-color: #{if @disabled, do: "var(--t-border-default)", else: "hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l))"}; color: var(--t-text-inverse); border-radius: var(--t-radius-button); cursor: #{if @disabled, do: "not-allowed", else: "pointer"}; border: none;"}
      >
        {@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} class="group">
      <summary
        class="flex justify-between items-center py-4 cursor-pointer list-none [&::-webkit-details-marker]:hidden"
        style="color: var(--t-text-primary);"
      >
        <span class="font-semibold">{@title}</span>
        <svg
          class="w-5 h-5 transition-transform duration-200 group-open:rotate-180"
          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="pb-4" style="color: var(--t-text-secondary);">
        {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="mt-8 divide-y"
      style="border-top: 1px solid var(--t-border-subtle); border-bottom: 1px solid var(--t-border-subtle); border-color: var(--t-border-subtle);"
    >
      <.accordion_item title="Description" open={true}>
        <p class="leading-relaxed">
          {@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="w-full text-sm">
            <thead>
              <tr style="border-bottom: 1px solid var(--t-border-subtle);">
                <th class="text-left py-2 font-semibold" style="color: var(--t-text-primary);">
                  Size
                </th>
                <th class="text-left py-2 font-semibold" style="color: var(--t-text-primary);">
                  Chest (cm)
                </th>
                <th class="text-left py-2 font-semibold" style="color: var(--t-text-primary);">
                  Length (cm)
                </th>
              </tr>
            </thead>
            <tbody>
              <%= for {size_row, idx} <- Enum.with_index(@sizes) do %>
                <tr style={
                  if idx < length(@sizes) - 1,
                    do: "border-bottom: 1px solid var(--t-border-subtle);",
                    else: ""
                }>
                  <td class="py-2">{size_row.size}</td>
                  <td class="py-2">{size_row.chest}</td>
                  <td class="py-2">{size_row.length}</td>
                </tr>
              <% end %>
            </tbody>
          </table>
        </.accordion_item>
      <% end %>

      <.accordion_item title="Shipping & Returns">
        <div class="flex flex-col gap-3">
          <div>
            <p class="font-semibold mb-1" style="color: var(--t-text-primary);">Delivery</p>
            <p class="text-sm">
              Free UK delivery on orders over £40. Standard delivery 3-5 working days. Express delivery available at checkout.
            </p>
          </div>
          <div>
            <p class="font-semibold mb-1" style="color: var(--t-text-primary);">Returns</p>
            <p class="text-sm">
              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
end
