defmodule Berrypod.Reviews.ReviewRequestWorker do
  @moduledoc """
  Sends review request emails after order delivery.

  Enqueued with a configurable delay (default 7 days) after an order is marked
  as delivered. At send time, checks which products in the order haven't been
  reviewed yet and sends a single email with links for each.

  Only one review request is sent per order. If the customer has already
  reviewed all products, no email is sent.
  """

  use Oban.Worker, queue: :mailer, max_attempts: 3

  alias Berrypod.{Orders, Reviews, Settings}
  alias Berrypod.Reviews.ReviewNotifier

  require Logger

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{"order_id" => order_id}}) do
    case Orders.get_order(order_id) do
      nil ->
        Logger.warning("Review request: order #{order_id} not found")
        {:cancel, :not_found}

      %{customer_email: nil} ->
        Logger.info("Review request: no customer email for order #{order_id}")
        :ok

      %{customer_email: ""} ->
        Logger.info("Review request: no customer email for order #{order_id}")
        :ok

      order ->
        send_review_request(order)
    end
  end

  defp send_review_request(order) do
    # Check suppression - review requests are marketing emails
    case Orders.check_suppression(order.customer_email) do
      :suppressed ->
        Logger.info("Review request: email suppressed for order #{order.order_number}")
        :ok

      :ok ->
        do_send_review_request(order)
    end
  end

  defp do_send_review_request(order) do
    # Find products in this order that haven't been reviewed yet
    unreviewable_products = get_unreviewable_products(order)

    if unreviewable_products == [] do
      Logger.info("Review request: all products already reviewed for order #{order.order_number}")
      :ok
    else
      case ReviewNotifier.deliver_review_request(order, unreviewable_products) do
        {:ok, _} ->
          Logger.info(
            "Review request sent to #{order.customer_email} for order #{order.order_number}"
          )

          :ok

        {:error, reason} ->
          Logger.error(
            "Review request failed for order #{order.order_number}: #{inspect(reason)}"
          )

          {:error, reason}
      end
    end
  end

  defp get_unreviewable_products(order) do
    order.items
    |> Enum.map(& &1.product_id)
    |> Enum.uniq()
    |> Enum.reject(&is_nil/1)
    |> Enum.reject(fn product_id ->
      # Already reviewed?
      not is_nil(Reviews.get_review_by_email_and_product(order.customer_email, product_id))
    end)
    |> Enum.map(fn product_id ->
      # Find the item details for this product
      item = Enum.find(order.items, &(&1.product_id == product_id))
      %{product_id: product_id, product_name: item.product_name}
    end)
  end

  @doc """
  Enqueues a review request job for an order.

  Called when an order is marked as delivered. Schedules the job based on
  the `review_request_delay_days` setting (default 7 days).
  """
  def enqueue(order_id) do
    delay_days = Settings.get_setting("review_request_delay_days", 7)
    delay_seconds = delay_days * 24 * 60 * 60

    %{order_id: order_id}
    |> new(schedule_in: delay_seconds)
    |> Oban.insert()
  end
end
