// Debian build: react/ink-based reporters (.tsx files) are not built.
// Only stream-based reporters are exposed; the default reporter is forced
// to "tap" by a patch in @tapjs/config.
import type { LoadedConfig } from '@tapjs/config'
import type { TAP, TestBase } from '@tapjs/core'
import { isStream, Minipass } from 'minipass'
import { Writable } from 'stream'
import { JSONReport, JSONStream } from './json.js'
import { JUnit } from './junit.js'
import { MarkdownStream } from './markdown.js'
import * as utils from './utils.js'

class TapStream extends Minipass<string> {}
const hooks: Record<string, never> = {}
const components: Record<string, never> = {}

export {
  JSONReport,
  JSONStream,
  MarkdownStream,
  JUnit,
  hooks,
  components,
  utils,
}

export interface TapReportOpts {
  test: TestBase
  config: LoadedConfig
}

export type Reporter = (opts: TapReportOpts) => any
export const types: Record<string, Reporter | typeof Minipass<string>> = {}
export const addType = (
  name: string,
  report: Reporter | typeof Minipass<string>,
) => {
  types[name] = report
}
addType('tap', TapStream)
addType('jsonstream', JSONStream)
addType('json', JSONReport)
addType('junit', JUnit)
addType('markdown', MarkdownStream)
addType('base', TapStream)
addType('terse', TapStream)
addType('min', TapStream)
addType('dot', TapStream)

export const Base = TapStream
export const Terse = TapStream
export const Min = TapStream
export const Dot = TapStream

export const report = async (
  Type: string | Reporter | typeof Minipass<string>,
  tap: TAP,
  _config: LoadedConfig,
  stdout: Writable = process.stdout,
) => {
  if (typeof Type === 'string') {
    if (types.hasOwnProperty(Type)) {
      Type = types[Type] as Reporter | typeof Minipass<string>
    } else {
      throw new TypeError(`unknown report type: ${Type}`)
    }
  }
  tap.register()
  const Ctor: any = isStream((Type as any).prototype) ? Type : TapStream
  const reporter: any = new Ctor({})
  ;(tap as any).pipe(reporter).pipe(stdout)
  return true
}
