"use strict"
var __createBinding =
  (this && this.__createBinding) ||
  (Object.create
    ? function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        Object.defineProperty(o, k2, {
          enumerable: true,
          get: function () {
            return m[k]
          }
        })
      }
    : function (o, m, k, k2) {
        if (k2 === undefined) k2 = k
        o[k2] = m[k]
      })
var __setModuleDefault =
  (this && this.__setModuleDefault) ||
  (Object.create
    ? function (o, v) {
        Object.defineProperty(o, "default", { enumerable: true, value: v })
      }
    : function (o, v) {
        o["default"] = v
      })
var __importStar =
  (this && this.__importStar) ||
  function (mod) {
    if (mod && mod.__esModule) return mod
    var result = {}
    if (mod != null)
      for (var k in mod)
        if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
          __createBinding(result, mod, k)
    __setModuleDefault(result, mod)
    return result
  }
Object.defineProperty(exports, "__esModule", { value: true })
exports.pretty =
  exports.defaultRenderer =
  exports.defaultErrorToLines =
  exports.prettyM =
  exports.prettyLines =
  exports.format =
  exports.times =
  exports.renderTrace =
  exports.causeToSequential =
  exports.renderToString =
  exports.parallelSegments =
  exports.linearSegments =
  exports.lines =
  exports.renderFail =
  exports.renderDie =
  exports.renderError =
  exports.renderInterrupt =
  exports.prefixBlock =
  exports.headTail =
  exports.Parallel =
  exports.Sequential =
  exports.Failure =
    void 0
// tracing: off
const A = __importStar(require("../../Collections/Immutable/Array"))
const tracing_1 = require("../../Fiber/tracing")
const Function_1 = require("../../Function")
const S = __importStar(require("../../IO"))
const O = __importStar(require("../../Option"))
function Failure(lines) {
  return {
    _tag: "Failure",
    lines
  }
}
exports.Failure = Failure
function Sequential(all) {
  return {
    _tag: "Sequential",
    all
  }
}
exports.Sequential = Sequential
function Parallel(all) {
  return {
    _tag: "Parallel",
    all
  }
}
exports.Parallel = Parallel
function headTail(a) {
  const x = [...a]
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  const head = x.shift()
  return [head, x]
}
exports.headTail = headTail
function prefixBlock(values, p1, p2) {
  return A.isNonEmpty(values)
    ? (([head, tail]) => [`${p1}${head}`, ...tail.map((_) => `${p2}${_}`)])(
        headTail(values)
      )
    : []
}
exports.prefixBlock = prefixBlock
function renderInterrupt(fiberId, trace, traceRenderer) {
  return Sequential([
    Failure([
      `An interrupt was produced by #${fiberId.seqNumber}.`,
      "",
      ...renderTrace(trace, traceRenderer)
    ])
  ])
}
exports.renderInterrupt = renderInterrupt
function renderError(error) {
  return lines(error.stack ? error.stack : String(error))
}
exports.renderError = renderError
function renderDie(error, trace, traceRenderer) {
  return Sequential([
    Failure([
      "An unchecked error was produced.",
      "",
      ...error,
      ...renderTrace(trace, traceRenderer)
    ])
  ])
}
exports.renderDie = renderDie
function renderFail(error, trace, traceRenderer) {
  return Sequential([
    Failure([
      "A checked error was not handled.",
      "",
      ...error,
      ...renderTrace(trace, traceRenderer)
    ])
  ])
}
exports.renderFail = renderFail
function lines(s) {
  return s.split("\n").map((s) => s.replace("\r", ""))
}
exports.lines = lines
function linearSegments(cause, renderer) {
  return S.gen(function* (_) {
    switch (cause._tag) {
      case "Then": {
        return [
          ...(yield* _(linearSegments(cause.left, renderer))),
          ...(yield* _(linearSegments(cause.right, renderer)))
        ]
      }
      default: {
        return (yield* _(causeToSequential(cause, renderer))).all
      }
    }
  })
}
exports.linearSegments = linearSegments
function parallelSegments(cause, renderer) {
  return S.gen(function* (_) {
    switch (cause._tag) {
      case "Both": {
        return [
          ...(yield* _(parallelSegments(cause.left, renderer))),
          ...(yield* _(parallelSegments(cause.right, renderer)))
        ]
      }
      default: {
        return [yield* _(causeToSequential(cause, renderer))]
      }
    }
  })
}
exports.parallelSegments = parallelSegments
function renderToString(u) {
  if (
    typeof u === "object" &&
    u != null &&
    "toString" in u &&
    typeof u["toString"] === "function" &&
    u["toString"] !== Object.prototype.toString
  ) {
    return u["toString"]()
  }
  return JSON.stringify(u, null, 2)
}
exports.renderToString = renderToString
function causeToSequential(cause, renderer) {
  return S.gen(function* (_) {
    switch (cause._tag) {
      case "Empty": {
        return Sequential([])
      }
      case "Fail": {
        return renderFail(
          renderer.renderError(cause.value),
          O.none,
          renderer.renderTrace
        )
      }
      case "Die": {
        return renderDie(
          renderer.renderUnknown(cause.value),
          O.none,
          renderer.renderTrace
        )
      }
      case "Interrupt": {
        return renderInterrupt(cause.fiberId, O.none, renderer.renderTrace)
      }
      case "Then": {
        return Sequential(yield* _(linearSegments(cause, renderer)))
      }
      case "Both": {
        return Sequential([Parallel(yield* _(parallelSegments(cause, renderer)))])
      }
      case "Traced": {
        switch (cause.cause._tag) {
          case "Fail": {
            return renderFail(
              renderer.renderError(cause.cause.value),
              O.some(cause.trace),
              renderer.renderTrace
            )
          }
          case "Die": {
            return renderDie(
              renderer.renderUnknown(cause.cause.value),
              O.some(cause.trace),
              renderer.renderTrace
            )
          }
          case "Interrupt": {
            return renderInterrupt(
              cause.cause.fiberId,
              O.some(cause.trace),
              renderer.renderTrace
            )
          }
          default: {
            return Sequential([
              Failure([
                "An error was rethrown with a new trace.",
                ...renderTrace(O.some(cause.trace), renderer.renderTrace)
              ]),
              ...(yield* _(causeToSequential(cause.cause, renderer))).all
            ])
          }
        }
      }
    }
  })
}
exports.causeToSequential = causeToSequential
function renderTrace(o, renderTrace) {
  return o._tag === "None" ? [] : lines(renderTrace(o.value))
}
exports.renderTrace = renderTrace
function times(s, n) {
  let h = ""
  for (let i = 0; i < n; i += 1) {
    h += s
  }
  return h
}
exports.times = times
function format(segment) {
  switch (segment._tag) {
    case "Failure": {
      return prefixBlock(segment.lines, "─", " ")
    }
    case "Parallel": {
      return [
        times("══╦", segment.all.length - 1) + "══╗",
        ...A.reduceRight_(segment.all, [], (current, acc) => [
          ...prefixBlock(acc, "  ║", "  ║"),
          ...prefixBlock(format(current), "  ", "  ")
        ])
      ]
    }
    case "Sequential": {
      return A.chain_(segment.all, (seg) => [
        "║",
        ...prefixBlock(format(seg), "╠", "║"),
        "▼"
      ])
    }
  }
}
exports.format = format
function prettyLines(cause, renderer) {
  return S.gen(function* (_) {
    const s = yield* _(causeToSequential(cause, renderer))
    if (s.all.length === 1 && s.all[0] && s.all[0]._tag === "Failure") {
      return s.all[0].lines
    }
    return O.getOrElse_(A.updateAt_(format(s), 0, "╥"), () => [])
  })
}
exports.prettyLines = prettyLines
function prettyM(cause, renderer) {
  return S.gen(function* (_) {
    const lines = yield* _(prettyLines(cause, renderer))
    return `\n${lines.join("\n")}`
  })
}
exports.prettyM = prettyM
function defaultErrorToLines(error) {
  return error instanceof Error ? renderError(error) : lines(renderToString(error))
}
exports.defaultErrorToLines = defaultErrorToLines
exports.defaultRenderer = {
  renderError: defaultErrorToLines,
  renderTrace: tracing_1.prettyTrace,
  renderUnknown: defaultErrorToLines
}
/**
 * Returns a `String` with the cause pretty-printed.
 */
const pretty = (cause, renderer = exports.defaultRenderer) =>
  S.run(prettyM(cause, renderer))
exports.pretty = pretty
//# sourceMappingURL=index.js.map
