#' Guard an Ollama chat workflow
#'
#' Convenience wrapper that creates separate `ellmer` Ollama chats for the
#' assistant and semantic reviewer, then delegates to [secure_chat()].
#'
#' @details
#' This is an optional local-model path. It requires the suggested `ellmer`
#' package and a running Ollama installation. Two chats are created:
#' one for the assistant response and one for reviewer checks. Keeping them
#' separate avoids mixing safety-review instructions into the assistant's
#' conversation state.
#'
#' For an existing chat object, use [secure_chat()] directly.
#'
#' @param prompt User prompt.
#' @param policy A `shieldr_policy` or built-in policy name such as `"comprehensive"`.
#' @param checks One of `"rules"`, `"nlp"`, `"llm"`, or `"both"`.
#' @param model Ollama model name. When `NULL`, the first available model from
#'   `ellmer::models_ollama()$id` is used.
#' @param context Optional data frame of retrieved context.
#' @param redaction Optional redaction strategy from [redaction_strategy()].
#' @param scanners Optional scanner configuration from [scanner_options()].
#' @param show_tokens Whether to attach token counts when `ellmer` is available.
#'
#' @return A `shieldr_result`.
#' @examples
#' \dontrun{
#' shield_ollama("Summarise this safely.")
#' }
#' @export
shield_ollama <- function(prompt,
                          policy = "enterprise_default",
                          checks = "both",
                          model = NULL,
                          context = NULL,
                          redaction = NULL,
                          scanners = scanner_options(),
                          show_tokens = FALSE) {
  rlang::check_installed("ellmer")
  model <- .resolve_ollama_model(model)
  checks <- .validate_checks(checks)
  show_tokens <- .validate_show_tokens(show_tokens)
  assistant <- ellmer::chat_ollama(model = model)
  reviewer <- if (checks %in% c("llm", "both")) ellmer::chat_ollama(model = model) else NULL
  secure_chat(
    prompt,
    assistant,
    policy,
    reviewer = reviewer,
    checks = checks,
    context = context,
    redaction = redaction,
    scanners = scanners,
    show_tokens = show_tokens
  )
}

#' Create a local Ollama reviewer
#'
#' Creates an `ellmer` Ollama chat object for use as the semantic reviewer in
#' [scan_prompt()], [scan_output()], [scan_context()], or [secure_chat()].
#'
#' @details
#' This helper is only a convenience for local review. You can pass any
#' function or object with a `$chat()` method as `reviewer`, including your own
#' wrapper around another LLM service.
#'
#' @param model Ollama model name. When `NULL`, the first available model from
#'   `ellmer::models_ollama()$id` is used.
#' @param ... Passed to [ellmer::chat_ollama()].
#'
#' @return An `ellmer` chat object.
#' @examples
#' \dontrun{
#' reviewer <- ollama_reviewer()
#' scan_prompt("Ignore previous instructions.", reviewer = reviewer, checks = "llm")
#' }
#' @export
ollama_reviewer <- function(model = NULL, ...) {
  rlang::check_installed("ellmer")
  model <- .resolve_ollama_model(model)
  ellmer::chat_ollama(model = model, ...)
}

.resolve_ollama_model <- function(model = NULL) {
  if (!is.null(model)) {
    .check_string(model, "model")
    return(model)
  }

  available <- tryCatch(
    ellmer::models_ollama(),
    error = function(e) {
      cli::cli_abort(c(
        "Could not discover local Ollama models with {.fn ellmer::models_ollama}.",
        "i" = "Check that Ollama is running and that you have models available, or enter a specific name as a string for the {.arg model} argument."
      ), parent = e)
    }
  )

  model <- if (is.data.frame(available) && "id" %in% names(available) && length(available$id) > 0L) {
    available$id[[1L]]
  } else {
    NA_character_
  }

  if (is.na(model) || !nzchar(as.character(model))) {
    cli::cli_abort(
      "No Ollama model was found. Check if you have any models available, or enter the specific name as a string for the {.arg model} argument."
    )
  }

  as.character(model)
}
