defmodule SimpleshopThemeWeb.Admin.Theme.Index do
  use SimpleshopThemeWeb, :live_view

  alias SimpleshopTheme.Settings
  alias SimpleshopTheme.Media
  alias SimpleshopTheme.Theme.{CSSGenerator, Presets, PreviewData}

  @impl true
  def mount(_params, _session, socket) do
    theme_settings = Settings.get_theme_settings()
    generated_css = CSSGenerator.generate(theme_settings)
    active_preset = Presets.detect_preset(theme_settings)

    preview_data = %{
      products: PreviewData.products(),
      cart_items: PreviewData.cart_items(),
      testimonials: PreviewData.testimonials(),
      categories: PreviewData.categories()
    }

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

    socket =
      socket
      |> assign(:theme_settings, theme_settings)
      |> assign(:generated_css, generated_css)
      |> assign(:preview_page, :home)
      |> assign(:presets_with_descriptions, Presets.all_with_descriptions())
      |> assign(:active_preset, active_preset)
      |> assign(:preview_data, preview_data)
      |> assign(:logo_image, logo_image)
      |> assign(:header_image, header_image)
      |> assign(:customise_open, false)
      |> assign(:sidebar_collapsed, false)
      |> assign(:cart_drawer_open, false)
      |> allow_upload(:logo_upload,
        accept: ~w(.png .jpg .jpeg .webp .svg),
        max_entries: 1,
        max_file_size: 2_000_000,
        auto_upload: true,
        progress: &handle_progress/3
      )
      |> allow_upload(:header_upload,
        accept: ~w(.png .jpg .jpeg .webp),
        max_entries: 1,
        max_file_size: 5_000_000,
        auto_upload: true,
        progress: &handle_progress/3
      )

    {:ok, socket}
  end

  defp handle_progress(:logo_upload, entry, socket) do
    if entry.done? do
      consume_uploaded_entries(socket, :logo_upload, fn %{path: path}, entry ->
        case Media.upload_from_entry(path, entry, "logo") do
          {:ok, image} ->
            Settings.update_theme_settings(%{logo_image_id: image.id})
            {:ok, image}

          {:error, _} = error ->
            error
        end
      end)
      |> case do
        [image | _] ->
          {:noreply, assign(socket, :logo_image, image)}

        _ ->
          {:noreply, socket}
      end
    else
      {:noreply, socket}
    end
  end

  defp handle_progress(:header_upload, entry, socket) do
    if entry.done? do
      consume_uploaded_entries(socket, :header_upload, fn %{path: path}, entry ->
        case Media.upload_from_entry(path, entry, "header") do
          {:ok, image} ->
            Settings.update_theme_settings(%{header_image_id: image.id})
            {:ok, image}

          {:error, _} = error ->
            error
        end
      end)
      |> case do
        [image | _] ->
          {:noreply, assign(socket, :header_image, image)}

        _ ->
          {:noreply, socket}
      end
    else
      {:noreply, socket}
    end
  end

  @impl true
  def handle_event("apply_preset", %{"preset" => preset_name}, socket) do
    preset_atom = String.to_existing_atom(preset_name)

    case Settings.apply_preset(preset_atom) do
      {:ok, theme_settings} ->
        generated_css = CSSGenerator.generate(theme_settings)

        socket =
          socket
          |> assign(:theme_settings, theme_settings)
          |> assign(:generated_css, generated_css)
          |> assign(:active_preset, preset_atom)
          |> put_flash(:info, "Applied #{preset_name} preset")

        {:noreply, socket}

      {:error, _} ->
        {:noreply, put_flash(socket, :error, "Failed to apply preset")}
    end
  end

  @impl true
  def handle_event("change_preview_page", %{"page" => page_name}, socket) do
    page_atom = String.to_existing_atom(page_name)

    socket =
      socket
      |> assign(:preview_page, page_atom)
      |> push_event("scroll-preview-top", %{})

    {:noreply, socket}
  end

  @impl true
  def handle_event("update_setting", %{"field" => field, "setting_value" => value}, socket) do
    field_atom = String.to_existing_atom(field)
    attrs = %{field_atom => value}

    case Settings.update_theme_settings(attrs) do
      {:ok, theme_settings} ->
        generated_css = CSSGenerator.generate(theme_settings)
        active_preset = Presets.detect_preset(theme_settings)

        socket =
          socket
          |> assign(:theme_settings, theme_settings)
          |> assign(:generated_css, generated_css)
          |> assign(:active_preset, active_preset)

        {:noreply, socket}

      {:error, _} ->
        {:noreply, socket}
    end
  end

  @impl true
  def handle_event("update_setting", %{"field" => field} = params, socket) do
    # For phx-change events from select/input elements, the value comes from the name attribute
    value = params[field] || params["#{field}_text"] || params["value"]

    if value do
      field_atom = String.to_existing_atom(field)
      attrs = %{field_atom => value}

      case Settings.update_theme_settings(attrs) do
        {:ok, theme_settings} ->
          generated_css = CSSGenerator.generate(theme_settings)
          active_preset = Presets.detect_preset(theme_settings)

          socket =
            socket
            |> assign(:theme_settings, theme_settings)
            |> assign(:generated_css, generated_css)
            |> assign(:active_preset, active_preset)

          {:noreply, socket}

        {:error, _} ->
          {:noreply, socket}
      end
    else
      {:noreply, socket}
    end
  end

  @impl true
  def handle_event("update_color", %{"field" => field, "value" => value}, socket) do
    field_atom = String.to_existing_atom(field)
    attrs = %{field_atom => value}

    case Settings.update_theme_settings(attrs) do
      {:ok, theme_settings} ->
        generated_css = CSSGenerator.generate(theme_settings)
        active_preset = Presets.detect_preset(theme_settings)

        socket =
          socket
          |> assign(:theme_settings, theme_settings)
          |> assign(:generated_css, generated_css)
          |> assign(:active_preset, active_preset)

        {:noreply, socket}

      {:error, _} ->
        {:noreply, socket}
    end
  end

  @impl true
  def handle_event("toggle_setting", %{"field" => field}, socket) do
    field_atom = String.to_existing_atom(field)
    current_value = Map.get(socket.assigns.theme_settings, field_atom)
    attrs = %{field_atom => !current_value}

    case Settings.update_theme_settings(attrs) do
      {:ok, theme_settings} ->
        generated_css = CSSGenerator.generate(theme_settings)
        active_preset = Presets.detect_preset(theme_settings)

        socket =
          socket
          |> assign(:theme_settings, theme_settings)
          |> assign(:generated_css, generated_css)
          |> assign(:active_preset, active_preset)

        {:noreply, socket}

      {:error, _} ->
        {:noreply, socket}
    end
  end

  @impl true
  def handle_event("save_theme", _params, socket) do
    socket = put_flash(socket, :info, "Theme saved successfully")
    {:noreply, socket}
  end

  @impl true
  def handle_event("remove_logo", _params, socket) do
    if logo = socket.assigns.logo_image do
      Media.delete_image(logo)
    end

    Settings.update_theme_settings(%{logo_image_id: nil})

    socket =
      socket
      |> assign(:logo_image, nil)
      |> put_flash(:info, "Logo removed")

    {:noreply, socket}
  end

  @impl true
  def handle_event("remove_header", _params, socket) do
    if header = socket.assigns.header_image do
      Media.delete_image(header)
    end

    Settings.update_theme_settings(%{header_image_id: nil})

    socket =
      socket
      |> assign(:header_image, nil)
      |> put_flash(:info, "Header image removed")

    {:noreply, socket}
  end

  @impl true
  def handle_event("cancel_upload", %{"ref" => ref, "upload" => upload_name}, socket) do
    upload_atom = String.to_existing_atom(upload_name)
    {:noreply, cancel_upload(socket, upload_atom, ref)}
  end

  @impl true
  def handle_event("toggle_customise", _params, socket) do
    {:noreply, assign(socket, :customise_open, !socket.assigns.customise_open)}
  end

  @impl true
  def handle_event("toggle_sidebar", _params, socket) do
    {:noreply, assign(socket, :sidebar_collapsed, !socket.assigns.sidebar_collapsed)}
  end

  @impl true
  def handle_event("open_cart_drawer", _params, socket) do
    {:noreply, assign(socket, :cart_drawer_open, true)}
  end

  @impl true
  def handle_event("close_cart_drawer", _params, socket) do
    {:noreply, assign(socket, :cart_drawer_open, false)}
  end

  @impl true
  def handle_event("noop", _params, socket) do
    {:noreply, socket}
  end

  def error_to_string(:too_large), do: "File is too large"
  def error_to_string(:too_many_files), do: "Too many files"
  def error_to_string(:not_accepted), do: "File type not accepted"
  def error_to_string(err), do: inspect(err)

  defp preview_assigns(assigns) do
    assign(assigns, %{
      mode: :preview,
      products: assigns.preview_data.products,
      categories: assigns.preview_data.categories,
      cart_items: PreviewData.cart_drawer_items(),
      cart_count: 2,
      cart_subtotal: "£72.00"
    })
  end

  # Preview page component — delegates to shared PageTemplates with preview-specific assigns
  attr :page, :atom, required: true
  attr :preview_data, :map, required: true
  attr :theme_settings, :map, required: true
  attr :logo_image, :any, required: true
  attr :header_image, :any, required: true
  attr :cart_drawer_open, :boolean, default: false

  defp preview_page(%{page: :home} = assigns) do
    assigns = preview_assigns(assigns)
    ~H"<SimpleshopThemeWeb.PageTemplates.home {assigns} />"
  end

  defp preview_page(%{page: :collection} = assigns) do
    assigns = preview_assigns(assigns)
    ~H"<SimpleshopThemeWeb.PageTemplates.collection {assigns} />"
  end

  defp preview_page(%{page: :pdp} = assigns) do
    product = List.first(assigns.preview_data.products)
    option_types = Map.get(product, :option_types) || []
    variants = Map.get(product, :variants) || []

    {selected_options, selected_variant} =
      case variants do
        [first | _] -> {first.options, first}
        [] -> {%{}, nil}
      end

    available_options =
      Enum.reduce(option_types, %{}, fn opt, acc ->
        values = Enum.map(opt.values, & &1.title)
        Map.put(acc, opt.name, values)
      end)

    display_price =
      if selected_variant, do: selected_variant.price, else: product.cheapest_price

    assigns =
      assigns
      |> preview_assigns()
      |> assign(:product, product)
      |> assign(:gallery_images, build_gallery_images(product))
      |> assign(:related_products, Enum.slice(assigns.preview_data.products, 1, 4))
      |> assign(:option_types, option_types)
      |> assign(:selected_options, selected_options)
      |> assign(:available_options, available_options)
      |> assign(:display_price, display_price)
      |> assign(:quantity, 1)

    ~H"<SimpleshopThemeWeb.PageTemplates.pdp {assigns} />"
  end

  defp preview_page(%{page: :cart} = assigns) do
    cart_items = assigns.preview_data.cart_items

    subtotal =
      Enum.reduce(cart_items, 0, fn item, acc ->
        acc + item.product.cheapest_price * item.quantity
      end)

    assigns =
      assigns
      |> preview_assigns()
      |> assign(:cart_page_items, cart_items)
      |> assign(:cart_page_subtotal, subtotal)

    ~H"<SimpleshopThemeWeb.PageTemplates.cart {assigns} />"
  end

  defp preview_page(%{page: :about} = assigns) do
    assigns =
      assigns
      |> preview_assigns()
      |> assign(%{
        active_page: "about",
        hero_title: "About the studio",
        hero_description: "Your story goes here – this is sample content for the demo shop",
        hero_background: :sunken,
        image_src: "/mockups/night-sky-blanket-3",
        image_alt: "Night sky blanket draped over a chair",
        content_blocks: PreviewData.about_content()
      })

    ~H"<SimpleshopThemeWeb.PageTemplates.content {assigns} />"
  end

  defp preview_page(%{page: :delivery} = assigns) do
    assigns =
      assigns
      |> preview_assigns()
      |> assign(%{
        active_page: "delivery",
        hero_title: "Delivery & returns",
        hero_description: "Everything you need to know about shipping and returns",
        content_blocks: PreviewData.delivery_content()
      })

    ~H"<SimpleshopThemeWeb.PageTemplates.content {assigns} />"
  end

  defp preview_page(%{page: :privacy} = assigns) do
    assigns =
      assigns
      |> preview_assigns()
      |> assign(%{
        active_page: "privacy",
        hero_title: "Privacy policy",
        hero_description: "How we handle your personal information",
        content_blocks: PreviewData.privacy_content()
      })

    ~H"<SimpleshopThemeWeb.PageTemplates.content {assigns} />"
  end

  defp preview_page(%{page: :terms} = assigns) do
    assigns =
      assigns
      |> preview_assigns()
      |> assign(%{
        active_page: "terms",
        hero_title: "Terms of service",
        hero_description: "The legal bits",
        content_blocks: PreviewData.terms_content()
      })

    ~H"<SimpleshopThemeWeb.PageTemplates.content {assigns} />"
  end

  defp preview_page(%{page: :contact} = assigns) do
    assigns = preview_assigns(assigns)
    ~H"<SimpleshopThemeWeb.PageTemplates.contact {assigns} />"
  end

  defp preview_page(%{page: :error} = assigns) do
    assigns =
      assigns
      |> preview_assigns()
      |> assign(%{
        error_code: "404",
        error_title: "Page Not Found",
        error_description:
          "Sorry, we couldn't find the page you're looking for. Perhaps you've mistyped the URL or the page has been moved."
      })

    ~H"<SimpleshopThemeWeb.PageTemplates.error {assigns} />"
  end

  defp build_gallery_images(product) do
    alias SimpleshopTheme.Products.ProductImage

    (Map.get(product, :images) || [])
    |> Enum.sort_by(& &1.position)
    |> Enum.map(fn img -> ProductImage.direct_url(img, 1200) end)
    |> Enum.reject(&is_nil/1)
    |> case do
      [] -> []
      urls -> urls
    end
  end
end
