defmodule BerrypodWeb.Admin.Media do
  use BerrypodWeb, :live_view

  alias Berrypod.Media

  @impl true
  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:page_title, "Media")
      |> assign(:filter_type, nil)
      |> assign(:filter_search, "")
      |> assign(:filter_orphans, false)
      |> assign(:pagination, nil)
      |> assign(:selected_image, nil)
      |> assign(:selected_usages, [])
      |> assign(:edit_form, nil)
      |> assign(:upload_alt, "")
      |> assign(:confirm_delete, false)
      |> assign(:metadata_status, :idle)
      |> allow_upload(:media_upload,
        accept: ~w(.png .jpg .jpeg .webp .svg .gif),
        max_entries: 1,
        max_file_size: 5_000_000,
        auto_upload: true,
        progress: &handle_progress/3
      )

    {:ok, socket}
  end

  @impl true
  def handle_params(params, _uri, socket) do
    page_num = Berrypod.Pagination.parse_page(params)
    opts = image_filter_opts(socket)
    page = Media.list_images_paginated([page: page_num] ++ opts)

    socket =
      socket
      |> assign(:pagination, page)
      |> stream(:images, page.items, reset: true)

    {:noreply, socket}
  end

  defp handle_progress(:media_upload, entry, socket) do
    if entry.done? do
      alt = socket.assigns.upload_alt

      consume_uploaded_entries(socket, :media_upload, fn %{path: path}, entry ->
        extra = if alt != "", do: %{alt: alt}, else: %{}
        Media.upload_from_entry(path, entry, "media", extra)
      end)
      |> case do
        [image | _] ->
          # Reload without BLOB to insert into stream
          image_without_blob = Media.get_image(image.id) |> Map.put(:data, nil)

          {:noreply,
           socket
           |> stream_insert(:images, image_without_blob, at: 0)
           |> assign(:upload_alt, "")
           |> put_flash(:info, "Image uploaded")}

        _ ->
          {:noreply, put_flash(socket, :error, "Upload failed")}
      end
    else
      {:noreply, socket}
    end
  end

  @impl true
  def handle_event("filter_type", %{"type" => type}, socket) do
    type = if type == "", do: nil, else: type

    {:noreply,
     socket
     |> assign(:filter_type, type)
     |> reload_images()}
  end

  def handle_event("filter_search", %{"value" => value}, socket) do
    {:noreply,
     socket
     |> assign(:filter_search, value)
     |> reload_images()}
  end

  def handle_event("toggle_orphans", _params, socket) do
    {:noreply,
     socket
     |> assign(:filter_orphans, !socket.assigns.filter_orphans)
     |> reload_images()}
  end

  def handle_event("select_image", %{"id" => id}, socket) do
    image = Media.get_image(id)

    if image do
      usages = Media.find_usages(id)

      form =
        to_form(
          %{
            "alt" => image.alt || "",
            "caption" => image.caption || "",
            "tags" => image.tags || ""
          },
          as: :metadata
        )

      {:noreply,
       socket
       |> assign(:selected_image, Map.put(image, :data, nil))
       |> assign(:selected_usages, usages)
       |> assign(:edit_form, form)
       |> assign(:confirm_delete, false)
       |> assign(:metadata_status, :idle)}
    else
      {:noreply, socket}
    end
  end

  def handle_event("deselect_image", _params, socket) do
    {:noreply,
     assign(socket,
       selected_image: nil,
       selected_usages: [],
       edit_form: nil,
       confirm_delete: false
     )}
  end

  def handle_event("update_metadata", %{"metadata" => params}, socket) do
    image = socket.assigns.selected_image

    case Media.update_image_metadata(image, params) do
      {:ok, updated} ->
        updated_no_blob = Map.put(updated, :data, nil)

        {:noreply,
         socket
         |> stream_insert(:images, updated_no_blob)
         |> assign(:selected_image, updated_no_blob)
         |> assign(:metadata_status, :saved)}

      {:error, _changeset} ->
        {:noreply, assign(socket, :metadata_status, :error)}
    end
  end

  def handle_event("confirm_delete", _params, socket) do
    {:noreply, assign(socket, :confirm_delete, true)}
  end

  def handle_event("cancel_delete", _params, socket) do
    {:noreply, assign(socket, :confirm_delete, false)}
  end

  def handle_event("delete_image", _params, socket) do
    image = socket.assigns.selected_image

    case Media.delete_with_cleanup(image) do
      {:ok, _} ->
        {:noreply,
         socket
         |> stream_delete(:images, image)
         |> assign(:selected_image, nil)
         |> assign(:selected_usages, [])
         |> assign(:edit_form, nil)
         |> assign(:confirm_delete, false)
         |> put_flash(:info, "Image deleted")}

      {:error, :in_use, _usages} ->
        {:noreply, put_flash(socket, :error, "Cannot delete — image is still in use")}
    end
  end

  def handle_event("set_upload_alt", %{"value" => value}, socket) do
    {:noreply, assign(socket, :upload_alt, value)}
  end

  # ── Private helpers ──────────────────────────────────────────────

  defp image_filter_opts(socket) do
    [
      type: socket.assigns.filter_type,
      search: if(socket.assigns.filter_search != "", do: socket.assigns.filter_search),
      tag: nil
    ]
    |> Enum.reject(fn {_, v} -> is_nil(v) end)
  end

  defp reload_images(socket) do
    if socket.assigns.filter_orphans do
      # Orphan mode: load all, filter in Elixir (no pagination)
      opts = image_filter_opts(socket)
      images = Media.list_images(opts)
      used = Media.used_image_ids()
      orphans = Enum.reject(images, &MapSet.member?(used, &1.id))

      socket
      |> assign(:pagination, nil)
      |> stream(:images, orphans, reset: true)
    else
      push_patch(socket, to: ~p"/admin/media")
    end
  end

  defp format_file_size(nil), do: "—"

  defp format_file_size(bytes) when bytes < 1024, do: "#{bytes} B"

  defp format_file_size(bytes) when bytes < 1_048_576 do
    kb = Float.round(bytes / 1024, 1)
    "#{kb} KB"
  end

  defp format_file_size(bytes) do
    mb = Float.round(bytes / 1_048_576, 1)
    "#{mb} MB"
  end

  defp format_dimensions(nil, _), do: "—"
  defp format_dimensions(_, nil), do: "—"
  defp format_dimensions(w, h), do: "#{w} × #{h}"

  defp type_badge_class("product"), do: "admin-badge admin-badge-sm admin-badge-info"
  defp type_badge_class("media"), do: "admin-badge admin-badge-sm admin-badge-accent"
  defp type_badge_class("logo"), do: "admin-badge admin-badge-sm admin-badge-warning"
  defp type_badge_class("header"), do: "admin-badge admin-badge-sm admin-badge-warning"
  defp type_badge_class("icon"), do: "admin-badge admin-badge-sm admin-badge-warning"
  defp type_badge_class(_), do: "admin-badge admin-badge-sm admin-badge-neutral"

  defp image_thumbnail_url(image) do
    cond do
      image.is_svg -> nil
      image.variants_status == "complete" -> "/image_cache/#{image.id}-thumb.jpg"
      true -> nil
    end
  end

  @impl true
  def render(assigns) do
    ~H"""
    <.header>
      Media
    </.header>

    <div class="media-layout">
      <%!-- upload zone --%>
      <div class="media-upload-zone" phx-drop-target={@uploads.media_upload.ref}>
        <form phx-change="set_upload_alt" class="media-upload-form">
          <div class="media-upload-row">
            <label class="admin-btn admin-btn-primary">
              <.icon name="hero-arrow-up-tray" class="size-4" /> Upload image
              <.live_file_input upload={@uploads.media_upload} class="sr-only" />
            </label>
            <input
              type="text"
              name="value"
              value={@upload_alt}
              placeholder="Alt text (recommended)"
              class="admin-input admin-input-fill"
              phx-debounce="200"
            />
          </div>
        </form>
        <%= for entry <- @uploads.media_upload.entries do %>
          <div class="media-upload-progress">
            <span>{entry.client_name}</span>
            <progress value={entry.progress} max="100">{entry.progress}%</progress>
          </div>
        <% end %>
        <%= for err <- upload_errors(@uploads.media_upload) do %>
          <p class="admin-error">{Phoenix.Naming.humanize(err)}</p>
        <% end %>
      </div>

      <%!-- filter bar --%>
      <div class="admin-filter-row">
        <form phx-change="filter_type" class="contents">
          <select name="type" class="admin-select">
            <option value="" selected={is_nil(@filter_type)}>All types</option>
            <option value="media" selected={@filter_type == "media"}>Media</option>
            <option value="product" selected={@filter_type == "product"}>Product</option>
            <option value="logo" selected={@filter_type == "logo"}>Logo</option>
            <option value="header" selected={@filter_type == "header"}>Header</option>
            <option value="icon" selected={@filter_type == "icon"}>Icon</option>
          </select>
        </form>
        <input
          type="search"
          placeholder="Search filename or alt text..."
          value={@filter_search}
          phx-keyup="filter_search"
          phx-debounce="300"
          class="admin-input admin-input-fill"
        />
        <button
          phx-click="toggle_orphans"
          class={[
            "admin-btn admin-btn-sm",
            @filter_orphans && "admin-btn-primary",
            !@filter_orphans && "admin-btn-ghost"
          ]}
        >
          <.icon name="hero-trash" class="size-4" /> Orphans
        </button>
      </div>

      <div class="media-main">
        <%!-- image grid + pagination --%>
        <div class="media-grid-wrapper">
          <div id="media-grid" phx-update="stream" class="media-grid">
            <div
              :for={{dom_id, image} <- @streams.images}
              id={dom_id}
              phx-click="select_image"
              phx-value-id={image.id}
              class={[
                "media-card",
                @selected_image && @selected_image.id == image.id && "media-card-selected"
              ]}
            >
              <div class="media-card-thumb">
                <%= if image.is_svg do %>
                  <div class="media-card-svg-placeholder">
                    <.icon name="hero-code-bracket" class="size-8" />
                    <span>SVG</span>
                  </div>
                <% else %>
                  <%= if thumb = image_thumbnail_url(image) do %>
                    <img src={thumb} alt={image.alt || image.filename} loading="lazy" />
                  <% else %>
                    <div class="media-card-svg-placeholder">
                      <.icon name="hero-photo" class="size-8" />
                    </div>
                  <% end %>
                <% end %>
              </div>
              <div class="media-card-info">
                <span class="media-card-filename" title={image.filename}>{image.filename}</span>
                <div class="media-card-meta">
                  <span class={type_badge_class(image.image_type)}>{image.image_type}</span>
                  <span class="media-card-size">{format_file_size(image.file_size)}</span>
                </div>
                <span
                  :if={!image.alt || image.alt == ""}
                  class="media-card-no-alt"
                  title="Missing alt text"
                >
                  <.icon name="hero-exclamation-triangle" class="size-3" /> No alt text
                </span>
              </div>
            </div>
          </div>

          <.admin_pagination :if={@pagination} page={@pagination} patch={~p"/admin/media"} />
        </div>

        <%!-- detail panel --%>
        <div :if={@selected_image} class="media-detail-scrim" phx-click="deselect_image"></div>
        <aside :if={@selected_image} class="media-detail">
          <div class="media-detail-header">
            <h3>Image details</h3>
            <button phx-click="deselect_image" class="admin-btn admin-btn-sm admin-btn-ghost">
              <.icon name="hero-x-mark" class="size-4" />
            </button>
          </div>

          <div class="media-detail-preview">
            <%= if @selected_image.is_svg do %>
              <div class="media-detail-svg">
                <.icon name="hero-code-bracket" class="size-12" />
                <span>SVG image</span>
              </div>
            <% else %>
              <%= if thumb = image_thumbnail_url(@selected_image) do %>
                <img src={thumb} alt={@selected_image.alt || @selected_image.filename} />
              <% end %>
            <% end %>
          </div>

          <dl class="media-detail-meta">
            <dt>Filename</dt>
            <dd>{@selected_image.filename}</dd>
            <dt>Type</dt>
            <dd>{@selected_image.image_type}</dd>
            <dt>Size</dt>
            <dd>{format_file_size(@selected_image.file_size)}</dd>
            <dt>Dimensions</dt>
            <dd>{format_dimensions(@selected_image.source_width, @selected_image.source_height)}</dd>
            <dt>Uploaded</dt>
            <dd>{Calendar.strftime(@selected_image.inserted_at, "%d %b %Y %H:%M")}</dd>
          </dl>

          <.form for={@edit_form} phx-submit="update_metadata" class="media-detail-form">
            <.input field={@edit_form[:alt]} label="Alt text" placeholder="Describe this image..." />
            <.input field={@edit_form[:caption]} label="Caption" placeholder="Optional caption..." />
            <.input field={@edit_form[:tags]} label="Tags" placeholder="hero, homepage, banner..." />
            <div class="admin-form-actions-sm">
              <button type="submit" class="admin-btn admin-btn-primary admin-btn-sm">
                Save metadata
              </button>
              <.inline_feedback status={@metadata_status} />
            </div>
          </.form>

          <%= if @selected_usages != [] do %>
            <div class="media-detail-usages">
              <h4>Used in</h4>
              <ul>
                <%= for usage <- @selected_usages do %>
                  <li>
                    <span class={type_badge_class(to_string(usage.type))}>{usage.type}</span>
                    {usage.label}
                  </li>
                <% end %>
              </ul>
            </div>
          <% end %>

          <div class="media-detail-actions">
            <%= if @confirm_delete do %>
              <p class="admin-error">
                <%= if @selected_usages != [] do %>
                  This image is in use. Deleting it may break pages.
                <% else %>
                  Are you sure?
                <% end %>
              </p>
              <div class="admin-row">
                <button phx-click="delete_image" class="admin-btn admin-btn-sm admin-btn-danger">
                  Yes, delete
                </button>
                <button phx-click="cancel_delete" class="admin-btn admin-btn-sm admin-btn-ghost">
                  Cancel
                </button>
              </div>
            <% else %>
              <button
                phx-click="confirm_delete"
                class="admin-btn admin-btn-sm admin-btn-ghost admin-text-error"
              >
                <.icon name="hero-trash" class="size-4" /> Delete image
              </button>
            <% end %>
          </div>
        </aside>
      </div>
    </div>
    """
  end
end
