import type { EditorState } from '../richTextTypes'

export interface EditorAction {
	type: 'command' | 'paste' | 'keyboard' | 'selection' | 'input'
	name: string
	timestamp: number
	details: { [key: string]: any }
	state: EditorStateSnapshot
}

export interface EditorStateSnapshot {
	content: string
	selection: {
		start: number
		end: number
		collapsed: boolean
		text: string
	} | null
	activeStyles: string[]
	caretPosition: {
		node: string // Node description
		offset: number
	} | null
}

export interface DebugSession {
	id: string
	startTime: number
	actions: EditorAction[]
}

export class EditorDebugger {
	private session: DebugSession
	private maxActions: number
	private isDevelopment: boolean

	constructor(maxActions = 1000) {
		this.maxActions = maxActions
		this.session = this.createNewSession()
		this.isDevelopment = import.meta.env.DEV
	}

	private createNewSession(): DebugSession {
		return {
			id: `session_${Date.now()}`,
			startTime: Date.now(),
			actions: []
		}
	}

	private getNodeDescription(node: Node): string {
		if (node.nodeType === Node.TEXT_NODE) {
			return `Text("${node.textContent?.slice(0, 20)}${node.textContent && node.textContent.length > 20 ? '...' : ''}")`
		}
		const element = node as Element
		return `${element.tagName.toLowerCase()}${element.id ? `#${element.id}` : ''}`
	}

	private captureState(state: EditorState): EditorStateSnapshot {
		if (!state.doc || !state.selection) {
			return {
				content: '',
				selection: null,
				activeStyles: [],
				caretPosition: null
			}
		}

		const { selection } = state
		const range = selection.rangeCount ? selection.getRangeAt(0) : null

		return {
			content: state.doc.body.innerHTML,
			selection: range
				? {
					start: range.startOffset,
					end: range.endOffset,
					collapsed: range.collapsed,
					text: range.toString()
				}
				: null,
			activeStyles: Array.from(state.selectedStyles),
			caretPosition: range
				? {
					node: this.getNodeDescription(range.startContainer),
					offset: range.startOffset
				}
				: null
		}
	}

	logCommand(command: string, value: string | undefined, state: EditorState) {
		this.addAction({
			type: 'command',
			name: command,
			timestamp: Date.now(),
			details: { value },
			state: this.captureState(state)
		})
	}

	logPaste(data: DataTransfer, state: EditorState) {
		this.addAction({
			type: 'paste',
			name: 'paste',
			timestamp: Date.now(),
			details: {
				html: data.getData('text/html'),
				text: data.getData('text/plain'),
				types: Array.from(data.types)
			},
			state: this.captureState(state)
		})
	}

	logKeyboard(event: KeyboardEvent, state: EditorState) {
		this.addAction({
			type: 'keyboard',
			name: 'keypress',
			timestamp: Date.now(),
			details: {
				key: event.key,
				code: event.code,
				ctrl: event.ctrlKey,
				alt: event.altKey,
				shift: event.shiftKey,
				meta: event.metaKey
			},
			state: this.captureState(state)
		})
	}

	logSelection(state: EditorState) {
		this.addAction({
			type: 'selection',
			name: 'selection_change',
			timestamp: Date.now(),
			details: {},
			state: this.captureState(state)
		})
	}

	logInput(inputType: string, data: string | null, state: EditorState) {
		this.addAction({
			type: 'input',
			name: inputType,
			timestamp: Date.now(),
			details: { data },
			state: this.captureState(state)
		})
	}

	private addAction(action: EditorAction) {
		this.session.actions.push(action)
		if (this.session.actions.length > this.maxActions) {
			this.session.actions.shift()
		}

		// Log to console in development
		if (this.isDevelopment) {
			console.log('Editor Action:', action)
		}
	}

	getSession(): DebugSession {
		return this.session
	}

	clearSession() {
		this.session = this.createNewSession()
	}

	exportSession(): string {
		return JSON.stringify(this.session, null, 2)
	}

	downloadSession() {
		const blob = new Blob([this.exportSession()], { type: 'application/json' })
		const url = URL.createObjectURL(blob)
		const a = document.createElement('a')
		a.href = url
		a.download = `editor_session_${this.session.id}.json`
		document.body.appendChild(a)
		a.click()
		document.body.removeChild(a)
		URL.revokeObjectURL(url)
	}

	exportSessionWithPrompt(userMessage?: string): string {
		const prompt = {
			message: userMessage || 'here is a debug log, can you analyze and fix accordingly?',
			session: this.session
		}
		return JSON.stringify(prompt, null, 2)
	}
}
