defmodule Towerops.Devices.BackupRequests do
  @moduledoc """
  Context for managing MikroTik device backup request tracking.
  """

  import Ecto.Query

  alias Towerops.Devices.BackupRequest
  alias Towerops.Repo

  @doc """
  Creates a new backup request for a device.
  """
  def create_request(device_id, job_id, source \\ "daily_cron") do
    attrs = %{
      device_id: device_id,
      job_id: job_id,
      requested_at: DateTime.utc_now(),
      status: "pending",
      source: source
    }

    %BackupRequest{}
    |> BackupRequest.changeset(attrs)
    |> Repo.insert()
  end

  @doc """
  Gets a backup request by job_id.
  Returns nil if not found.
  """
  def get_request_by_job_id(job_id) do
    Repo.one(from(r in BackupRequest, where: r.job_id == ^job_id))
  end

  @doc """
  Updates a backup request status and sets completed_at.
  """
  def update_request_status(request_id, status, error_message) do
    request = Repo.get!(BackupRequest, request_id)

    attrs = %{
      status: status,
      completed_at: DateTime.utc_now(),
      error_message: error_message
    }

    request
    |> BackupRequest.changeset(attrs)
    |> Repo.update()
  end

  @doc """
  Marks all pending requests older than cutoff as timeout.
  Returns count of updated requests.
  """
  def mark_timed_out_requests(cutoff) do
    {count, _} =
      Repo.update_all(from(r in BackupRequest, where: r.status == "pending", where: r.requested_at < ^cutoff),
        set: [status: "timeout", completed_at: DateTime.utc_now(), error_message: "Request timed out"]
      )

    count
  end

  @doc """
  Returns summary of backup request statuses since given datetime.
  """
  def summary_since(since) do
    result =
      from(r in BackupRequest,
        where: r.requested_at >= ^since,
        group_by: r.status,
        select: {r.status, count(r.id)}
      )
      |> Repo.all()
      |> Map.new()

    %{
      success: Map.get(result, "success", 0),
      failed: Map.get(result, "failed", 0),
      timeout: Map.get(result, "timeout", 0),
      pending: Map.get(result, "pending", 0)
    }
  end

  @doc """
  Lists devices with failed or timeout requests since given datetime.
  Returns list of maps with device_id, status, and error_message.
  """
  def list_failed_devices_since(since) do
    Repo.all(
      from(r in BackupRequest,
        where: r.requested_at >= ^since,
        where: r.status in ["failed", "timeout"],
        select: %{device_id: r.device_id, status: r.status, error_message: r.error_message}
      )
    )
  end
end
