defmodule SimpleshopThemeWeb.ImageController do
  use SimpleshopThemeWeb, :controller

  alias SimpleshopTheme.Media
  alias SimpleshopTheme.Media.SVGRecolorer

  @doc """
  Serves an image from the database by ID.

  Images are served with aggressive caching headers since they are
  immutable once uploaded.
  """
  def show(conn, %{"id" => id}) do
    case Media.get_image(id) do
      nil ->
        send_resp(conn, 404, "Image not found")

      image ->
        conn
        |> put_resp_content_type(image.content_type)
        |> put_resp_header("cache-control", "public, max-age=31536000, immutable")
        |> put_resp_header("etag", ~s("#{image.id}"))
        |> send_resp(200, image.data)
    end
  end

  @doc """
  Serves a thumbnail of an image if available, otherwise falls back to full image.
  """
  def thumbnail(conn, %{"id" => id}) do
    case Media.get_image(id) do
      nil ->
        send_resp(conn, 404, "Image not found")

      %{thumbnail_data: thumbnail_data} = image when not is_nil(thumbnail_data) ->
        conn
        |> put_resp_content_type("image/jpeg")
        |> put_resp_header("cache-control", "public, max-age=31536000, immutable")
        |> put_resp_header("etag", ~s("#{image.id}-thumb"))
        |> send_resp(200, thumbnail_data)

      image ->
        conn
        |> put_resp_content_type(image.content_type)
        |> put_resp_header("cache-control", "public, max-age=31536000, immutable")
        |> put_resp_header("etag", ~s("#{image.id}"))
        |> send_resp(200, image.data)
    end
  end

  @doc """
  Serves an SVG image recolored with the specified color.

  The color should be a hex color code (with or without the leading #).
  Only works with SVG images.
  """
  def recolored_svg(conn, %{"id" => id, "color" => color}) do
    clean_color = normalize_color(color)

    with true <- SVGRecolorer.valid_hex_color?(clean_color),
         %{is_svg: true, svg_content: svg} when not is_nil(svg) <- Media.get_image(id) do
      recolored = SVGRecolorer.recolor(svg, clean_color)

      conn
      |> put_resp_content_type("image/svg+xml")
      |> put_resp_header("cache-control", "public, max-age=3600")
      |> put_resp_header("etag", ~s("#{id}-#{clean_color}"))
      |> send_resp(200, recolored)
    else
      false ->
        send_resp(conn, 400, "Invalid color format")

      nil ->
        send_resp(conn, 404, "Image not found")

      %{is_svg: false} ->
        send_resp(conn, 400, "Image is not an SVG")

      %{svg_content: nil} ->
        send_resp(conn, 400, "SVG content not available")
    end
  end

  defp normalize_color(color) do
    color = String.trim(color)

    if String.starts_with?(color, "#") do
      color
    else
      "#" <> color
    end
  end
end
