import { NodeVariableRegex, SystemVariableRegex, EnvVariableRegex } from '@/utils/varReg'

export type VariableType = 'node' | 'sys' | 'env'

export function textToEditorState(text: string) {
	const paragraph = text && typeof text === 'string' ? text.split('\n') : ['']

	return JSON.stringify({
		root: {
			children: paragraph.map((p) => {
				const segments = splitTextByVariableSegments(p)
				const children = segments
					.map((segment) => {
						if (segment.kind === 'text') {
							if (!segment.text.length) return null
							return {
								detail: 0,
								format: 0,
								mode: 'normal',
								style: '',
								text: segment.text,
								type: 'text',
								version: 1
							}
						}
						return {
							className: `${segment.varType}-label`,
							text: segment.text,
							format: '',
							type: 'var-label',
							version: 1
						}
					})
					.filter((item) => item !== null)

				return {
					children: children.length
						? children
						: [
								{
									detail: 0,
									format: 0,
									mode: 'normal',
									style: '',
									text: '',
									type: 'text',
									version: 1
								}
							],
					direction: 'ltr',
					format: '',
					indent: 0,
					type: 'paragraph',
					version: 1
				}
			}),
			direction: 'ltr',
			format: '',
			indent: 0,
			type: 'root',
			version: 1
		}
	})
}

export type VariableMatch = {
	start: number
	end: number
	raw: string
	name: string
	type: VariableType
}

export type TextSegment = {
	kind: 'text'
	text: string
}

export type VariableSegment = {
	kind: 'variable'
	text: string
	varType: VariableType
	name: string
}

export type PromptEditorSegment = TextSegment | VariableSegment

function collectMatches(text: string, reg: RegExp, type: VariableType): VariableMatch[] {
	const globalReg = new RegExp(reg.source, 'g')
	const list: VariableMatch[] = []

	for (const match of text.matchAll(globalReg)) {
		const raw = match[0] ?? ''
		const name = match[1] ?? ''
		const start = match.index ?? -1
		const end = start + raw.length

		if (start < 0 || !raw) continue

		list.push({
			start,
			end,
			raw,
			name,
			type
		})
	}

	return list
}

export function getVariableMatches(text: string): VariableMatch[] {
	const candidates = [
		...collectMatches(text, NodeVariableRegex, 'node'),
		...collectMatches(text, SystemVariableRegex, 'sys'),
		...collectMatches(text, EnvVariableRegex, 'env')
	]

	return candidates.sort((a, b) => a.start - b.start)
}

export function getMatch(text: string): VariableMatch | null {
	const candidates = getVariableMatches(text)

	if (!candidates.length) return null

	return candidates[0] ?? null
}

export function splitTextByVariableSegments(text: string): PromptEditorSegment[] {
	if (!text.length) {
		return [{ kind: 'text', text: '' }]
	}

	const matches = getVariableMatches(text)
	if (!matches.length) {
		return [{ kind: 'text', text }]
	}

	const result: PromptEditorSegment[] = []
	let cursor = 0

	for (const match of matches) {
		if (match.start < cursor) continue

		if (match.start > cursor) {
			result.push({
				kind: 'text',
				text: text.slice(cursor, match.start)
			})
		}

		result.push({
			kind: 'variable',
			text: match.raw,
			varType: match.type,
			name: match.name
		})

		cursor = match.end
	}

	if (cursor < text.length) {
		result.push({
			kind: 'text',
			text: text.slice(cursor)
		})
	}

	return result.length ? result : [{ kind: 'text', text }]
}

function testWholeVariable(regex: RegExp, value: string) {
	const exactReg = new RegExp(`^${regex.source}$`)
	return exactReg.test(value)
}

export function getVariableTypeByValue(value: string): VariableType | null {
	if (testWholeVariable(NodeVariableRegex, value)) return 'node'
	if (testWholeVariable(SystemVariableRegex, value)) return 'sys'
	if (testWholeVariable(EnvVariableRegex, value)) return 'env'
	return null
}
