defmodule ZoeyscomputerWeb.ImageController do
  use ZoeyscomputerWeb, :controller

  import Mogrify

  alias Zoeyscomputer.IdGenerator
  alias Zoeyscomputer.Images
  alias Zoeyscomputer.Images.Image

  action_fallback ZoeyscomputerWeb.FallbackController

  def index(conn, _params) do
    images = Images.list_images()
    render(conn, :index, images: images)
  end

  def create(conn, %{"file" => upload}) do
    user = conn.assigns.current_user

    case handle_upload(upload) do
      {:ok, s3_key} ->
        # Fixed: create_image takes one argument (the params map)
        case Images.create_image(%{file: s3_key, user_id: user.id}) do
          {:ok, image} ->
            conn
            |> put_status(:created)
            |> put_resp_header("location", ~p"/api/images/#{image}")
            |> json(%{
              message: "File uploaded successfully",
              url: get_public_url(s3_key),
              image: image
            })

          {:error, changeset} ->
            conn
            |> put_status(:unprocessable_entity)
            |> json(%{
              error: "Database save failed",
              details: changeset_error_to_string(changeset)
            })
        end

      {:error, reason} ->
        conn
        |> put_status(:unprocessable_entity)
        |> json(%{
          error: "Upload failed",
          reason: inspect(reason)
        })
    end
  end

  defp changeset_error_to_string(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
      Enum.reduce(opts, msg, fn {key, value}, acc ->
        String.replace(acc, "%{#{key}}", to_string(value))
      end)
    end)
  end

  defp handle_upload(upload) do
    extension = Path.extname(upload.filename)
    id = IdGenerator.generate()
    key = "uploads/#{id}.png"
    bucket = "imgs"

    local_path = "/tmp/#{id}#{extension}"

    IO.puts("upload path: #{upload.path}")
    {:ok, file_binary} = File.read(upload.path)

    File.write!(local_path, file_binary)

    IO.puts("wrote to #{local_path}")
    image = open(local_path) |> format("png") |> save()
    IO.inspect(image)

    {:ok, new_file_binary} = File.read(image.path)

    case ExAws.S3.put_object(bucket, key, new_file_binary, %{content_type: "image/png"})
         |> ExAws.request() do
      {:ok, _response} -> {:ok, id}
      {:error, reason} -> {:error, reason}
    end
  end

  defp get_public_url(key) do
    "https://zoeys.computer/images/#{key}"
  end

  def show(conn, %{"id" => id}) do
    image = Images.get_image!(id)
    render(conn, :show, image: image)
  end

  def update(conn, %{"id" => id, "image" => image_params}) do
    image = Images.get_image!(id)

    with {:ok, %Image{} = image} <- Images.update_image(image, image_params) do
      render(conn, :show, image: image)
    end
  end

  def delete(conn, %{"id" => id}) do
    image = Images.get_image!(id)

    case ExAws.S3.delete_object("imgs", image.file)
         |> ExAws.request() do
      {:ok, _response} -> {:ok, image.file}
      {:error, reason} -> {:error, reason}
    end

    with {:ok, %Image{}} <- Images.delete_image(image) do
      send_resp(conn, :no_content, "")
    end
  end
end
