// this cannot be located at source/brower.ts as otherwise it would become the browser entry

// Imports
import { Transform } from '../transform.ts'

/** Mapping of ANSI color codes into a CSS style */
export interface Styles {
	[key: string]: {
		/** The ANSI color code used to start the style */
		start: string
		/** The ANSI color code used to end the style */
		end: string
		/** The CSS style value */
		value: string
	}
}

/** Configuration optons for the Caterpillar Browser Transform */
export interface BrowserOptions {
	/** Use to override the default value of {@link Filter.color} */
	color?: boolean
	/** Use to override the default value of {@link Filter.console} */
	output?: boolean
	/** Use to override the default value of {@link Filter.styles} */
	styles?: Styles
}

/**
 * Convert human readable Caterpillar entries into browser compatible entries.
 * @example
 * ``` javascript
 * import { Logger, Human, Browser } from 'caterpillar'
 * const logger = new Logger()
 * logger.pipe(new Human()).pipe(new Browser())
 * logger.log('info', 'some', {data: 'oh yeah'}, 42)
 * ```
 */
export class Browser extends Transform {
	/** Whether or not we should use color. */
	public color: boolean = true

	/** Whether or not we should write to the browser console. */
	public output: boolean = true

	/** The objects that tell our browser transform how to convert terminal colours into console colours. */
	public styles: Styles = {
		red: {
			start: '31',
			end: '39',
			value: 'color:red',
		},
		yellow: {
			start: '33',
			end: '39',
			value: 'color:orange',
		},
		green: {
			start: '32',
			end: '39',
			value: 'color:green',
		},
		bright: {
			start: '1',
			end: '22',
			value: 'font-weight:bold',
		},
		dim: {
			start: '2',
			end: '22',
			value: 'color:lightGray',
		},
		italic: {
			start: '3',
			end: '23',
			value: 'font-style:italic',
		},
		underline: {
			start: '4',
			end: '24',
			value: 'text-decoration:underline',
		},
	}

	/** Create our instance and apply our configuraiton options. */
	constructor(opts?: BrowserOptions) {
		super()

		// options
		if (opts?.color != null) this.color = opts.color
		if (opts?.output != null) this.output = opts.output
		if (opts?.styles != null) this.styles = opts.styles
	}

	/**
	 * Convert a human readable Caterpillar entry into a format that browser consoles can understand.
	 * And if the `write` config property is `true` (it is by default), write the result to the browser console.
	 */
	format(message: string): string[] {
		// Prepare
		const { color, styles, output } = this

		// Replace caterpillar-human formatted entry
		/* eslint no-control-regex:0 */
		const args: string[] = []
		const result = message.replace(
			/\u001b\[([0-9]+)m(.+?)\u001b\[([0-9]+)m/g,
			function (match, start, content, end) {
				// Check
				if (color === false) return content

				// Prepare
				let matchedStyle, style

				// Find the matcing style for this combination
				for (const key in styles) {
					if (styles.hasOwnProperty(key)) {
						style = styles[key]
						if (
							String(style.start) === String(start) &&
							String(style.end) === String(end)
						) {
							matchedStyle = style
							break
						}
					}
				}

				// Check
				if (!matchedStyle) return content

				// Push the style
				args.push(matchedStyle.value)
				args.push(content)
				args.push('color:default; font:default; text-decoration:default')
				return '%c%s%c'
			}
		)

		// Final format
		const parts = [result.trim()].concat(args)

		// Write
		/* eslint no-console:0 */
		if (output) console.log(...parts)

		// Return
		return parts
	}
}

export default Browser
