import {
	createContext,
	type Message,
	type TestTextAgent,
	type StepTracer,
	type Logger
} from '@recombine-ai/engine'
import { getAgentFactories } from '../get-agent-factories'
import { getRootPath } from '../get-root-path'

export async function loadAgents(props: {
	agentId: string
	getMessages: () => Message[]
	sendMessage: (message: Message | string) => Promise<void>
	stepTracer: StepTracer
	logger?: Logger
	context?: Record<string, any>
	timeoutSeconds: number
}): Promise<void> {
	const {
		agentId,
		getMessages,
		sendMessage,
		stepTracer: stepTracer,
		logger: providedLogger,
		context,
		timeoutSeconds
	} = props
	const { factories } = await getAgentFactories(await getRootPath())
	const factory = factories[agentId]
	if (!factory) throw new Error('Factory not found')

	// Minimal stubs
	const logger = providedLogger || {
		log: () => {},
		debug: () => {},
		error: () => {},
		warn: () => {}
	}
	const scheduler = {
		clearAllPendingActions: async () => {},
		registerAction: () => async () => {},
		triggerAction: async () => {},
		serialize: () => ({}) as any,
		setState: (_: any) => {}
	}
	const ctx = createContext({})
	if (context && typeof context === 'object') {
		// Apply provided context before agent lifecycle
		ctx.swap(context)
	}

	// Maintain in-run history so sendMessage appends to it, mirroring backend behavior
	const history = getMessages()
	const getMessagesWithHistory = () => history
	const sendMessageWithHistory = async (message: Message | string) => {
		const m =
			typeof message === 'string' ? ({ sender: 'agent', text: message } as Message) : message
		try {
			history.push(m)
		} catch {
			// Best-effort: if history is immutable, ignore push errors
			logger.log('Failed to push message to history:', m)
		}
		await sendMessage(m)
	}

	const agent = (await factory({
		stepTracer: stepTracer,
		tracer: {
			addStep: (step) => {}
		},
		logger: logger,
		scheduler: scheduler as any,
		getMessages: getMessagesWithHistory,
		sendMessage: sendMessageWithHistory,
		sendAction: async () => {},
		ctx
	})) as TestTextAgent

	process.on('unhandledRejection', (r) => {
		console.error('UNHANDLED', r)
	})

	try {
		await agent.respondToMessage()
		await new Promise((resolve) => setTimeout(resolve, timeoutSeconds * 1000))
	} catch (err) {
		const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err)
		const stack = err instanceof Error ? err.stack : undefined
		try {
			logger.error('Error in agent.respondToMessage():', msg)
		} catch {
			/* noop */
		}
		if (stack) {
			try {
				logger.error(stack)
			} catch {
				/* noop */
			}
		}
	}
}
