/** @module
@summary Combine and inspect findings returned by reviewer and verifier agents.

Use `feedbackHasErrors` to decide whether another attempt is needed and
`renderFeedback` to give the findings to that attempt. `mergeFeedback` and
`flattenFeedback` preserve failures. `failOpenFeedback` discards failures
when the caller deliberately allows an unavailable review.
*/

/** One review or verification finding. `error` marks a blocking problem.
A false value can mark advice or a satisfied point. `source` links to a
page used to check the finding. */
export type Feedback = {
  error: boolean;
  feedback: string;
  source?: string
}

export def mergeFeedback(
  a: Result<Feedback[]>,
  b: Result<Feedback[]>,
): Result<Feedback[]> {
  """
  Concatenate successful finding lists, returning the first failure if either input failed.
  """

  if (a is success(aVal)) {
    if (b is success(bVal)) {
      return success([...aVal, ...bVal])
    } else {
      return b
    }
  } else {
    return a
  }
}

export def flattenFeedback(feedback: Result<Feedback[]>[]): Result<Feedback[]> {
  """
  Combine finding lists, returning the first failed Result if one is present.
  """
  let merged: Result<Feedback[]> = success([])
  for (f in feedback) {
    merged = mergeFeedback(merged, f)
  }
  return merged
}

def feedbackToString(f: Feedback): string {
  let line = `Feedback: ${f.feedback}`
  if (f.error) {
    line = `Error: ${f.feedback}`
  }
  if (f.source != null && f.source != "") {
    line = "${line} (source: ${f.source})"
  }
  return line
}

export def renderFeedback(feedback: Result<Feedback[]>): string {
  """
  Render findings as paragraphs, or return the failure message when the review failed.
  """
  if (feedback is success(val)) {
    return map(val, feedbackToString).join("\n\n")
  }
  return feedback.error
}

export def feedbackHasErrors(feedback: Result<Feedback[]>): boolean {
  """
  Return whether findings include an error or the review itself failed.
  """
  if (feedback is success(val)) {
    return some(val, \item -> item.error)
  }
  return true
}

export def failOpenFeedback(feedback: Result<Feedback[]>): Result<Feedback[]> {
  """
  Keep successful findings and turn failures into an empty finding list.
  """
  return match(feedback) {
    success(items) => success(items)
    failure(_) => success([])
  }
}
