defmodule SimpleshopThemeWeb.ShopLive.ProductShow do
  use SimpleshopThemeWeb, :live_view

  alias SimpleshopTheme.Cart
  alias SimpleshopTheme.Settings
  alias SimpleshopTheme.Media
  alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}

  @impl true
  def mount(%{"id" => id}, _session, socket) do
    theme_settings = Settings.get_theme_settings()

    generated_css =
      case CSSCache.get() do
        {:ok, css} ->
          css

        :miss ->
          css = CSSGenerator.generate(theme_settings)
          CSSCache.put(css)
          css
      end

    logo_image = Media.get_logo()
    header_image = Media.get_header()

    products = PreviewData.products()

    # Find product by slug or ID (real products use slugs, mock data uses string IDs)
    product = find_product(products, id)

    # Get related products (exclude current product, take 4)
    related_products =
      products
      |> Enum.reject(fn p -> p.id == product.id end)
      |> Enum.take(4)

    # Build gallery images from local image_id or external URL
    gallery_images =
      [
        image_src(product[:image_id], product[:image_url]),
        image_src(product[:hover_image_id], product[:hover_image_url])
      ]
      |> Enum.reject(&is_nil/1)

    # Initialize variant selection
    option_types = product[:option_types] || []
    variants = product[:variants] || []
    {selected_options, selected_variant} = initialize_variant_selection(variants)
    available_options = compute_available_options(option_types, variants, selected_options)
    display_price = variant_price(selected_variant, product)

    socket =
      socket
      |> assign(:page_title, product.name)
      |> assign(:theme_settings, theme_settings)
      |> assign(:generated_css, generated_css)
      |> assign(:logo_image, logo_image)
      |> assign(:header_image, header_image)
      |> assign(:product, product)
      |> assign(:gallery_images, gallery_images)
      |> assign(:related_products, related_products)
      |> assign(:quantity, 1)
      |> assign(:mode, :shop)
      |> assign(:option_types, option_types)
      |> assign(:variants, variants)
      |> assign(:selected_options, selected_options)
      |> assign(:selected_variant, selected_variant)
      |> assign(:available_options, available_options)
      |> assign(:display_price, display_price)

    {:ok, socket}
  end

  # Find product by slug first (real products), then try ID match (mock data)
  defp find_product(products, id) do
    Enum.find(products, fn p -> p[:slug] == id end) ||
      Enum.find(products, fn p -> p.id == id end) ||
      List.first(products)
  end

  # Build image source URL - prefer local image_id, fall back to external URL
  defp image_src(image_id, _url) when is_binary(image_id) do
    "/images/#{image_id}/variant/1200.webp"
  end

  defp image_src(_, url) when is_binary(url), do: url
  defp image_src(_, _), do: nil

  # Select first available variant by default
  defp initialize_variant_selection([first | _] = _variants) do
    {first.options, first}
  end

  defp initialize_variant_selection([]) do
    {%{}, nil}
  end

  # Compute which option values are available given current selection
  defp compute_available_options(option_types, variants, selected_options) do
    Enum.reduce(option_types, %{}, fn opt_type, acc ->
      # For each option type, find which values have at least one available variant
      # when combined with the other selected options
      other_options = Map.delete(selected_options, opt_type.name)

      available_values =
        variants
        |> Enum.filter(fn v ->
          v.is_available &&
            Enum.all?(other_options, fn {k, selected_val} ->
              v.options[k] == selected_val
            end)
        end)
        |> Enum.map(fn v -> v.options[opt_type.name] end)
        |> Enum.uniq()

      Map.put(acc, opt_type.name, available_values)
    end)
  end

  defp variant_price(%{price: price}, _product) when is_integer(price), do: price
  defp variant_price(_, %{price: price}), do: price
  defp variant_price(_, _), do: 0

  defp find_variant(variants, selected_options) do
    Enum.find(variants, fn v -> v.options == selected_options end)
  end

  @impl true
  def handle_event("select_option", %{"option" => option_name, "value" => value}, socket) do
    selected_options = Map.put(socket.assigns.selected_options, option_name, value)

    # Find matching variant
    selected_variant = find_variant(socket.assigns.variants, selected_options)

    # Recompute available options based on new selection
    available_options =
      compute_available_options(
        socket.assigns.option_types,
        socket.assigns.variants,
        selected_options
      )

    socket =
      socket
      |> assign(:selected_options, selected_options)
      |> assign(:selected_variant, selected_variant)
      |> assign(:available_options, available_options)
      |> assign(:display_price, variant_price(selected_variant, socket.assigns.product))

    {:noreply, socket}
  end

  @impl true
  def handle_event("add_to_cart", _params, socket) do
    variant = socket.assigns.selected_variant

    if variant do
      cart = Cart.add_item(socket.assigns.raw_cart, variant.id, socket.assigns.quantity)

      socket =
        socket
        |> SimpleshopThemeWeb.CartHook.broadcast_and_update(cart)
        |> assign(:cart_drawer_open, true)
        |> assign(:cart_status, "#{socket.assigns.product.name} added to cart")

      {:noreply, socket}
    else
      {:noreply, socket}
    end
  end

  @impl true
  def render(assigns) do
    ~H"""
    <SimpleshopThemeWeb.PageTemplates.pdp
      theme_settings={@theme_settings}
      logo_image={@logo_image}
      header_image={@header_image}
      product={@product}
      gallery_images={@gallery_images}
      related_products={@related_products}
      quantity={@quantity}
      mode={@mode}
      cart_items={@cart_items}
      cart_count={@cart_count}
      cart_subtotal={@cart_subtotal}
      cart_drawer_open={@cart_drawer_open}
      cart_status={@cart_status}
      option_types={@option_types}
      selected_options={@selected_options}
      available_options={@available_options}
      display_price={@display_price}
    />
    """
  end
end
