import type { Logger, Scheduler, SendAction } from '@recombine-ai/engine'
import type { DelayedActions } from '../lib/ws-message'

export type DelayedActionRegistry<T> = Record<
	string,
	{ at: string | null; handler: (data: T) => Promise<unknown>; data: T | null }
>

export interface BosunScheduler extends Scheduler {
	triggerAction: (actionName: string) => Promise<void>
	serialize: () => DelayedActions
	setState(state: DelayedActions): void
}

interface Props {
	logger: Logger
	sendAction: SendAction
	onUpdate: (actions: DelayedActions) => void
}
export function createScheduler(
	{ logger, sendAction, onUpdate }: Props,
	delayedActions: DelayedActionRegistry<string> = {}
) {
	const scheduler: BosunScheduler = {
		clearAllPendingActions: async () => {
			sendAction({
				id: Math.random().toString(),
				type: 'Scheduler',
				state: 'completed',
				message: 'Clear all pending actions'
			})
			Object.keys(delayedActions).forEach((actionName) => {
				delayedActions[actionName] = {
					at: null,
					handler: delayedActions[actionName].handler,
					data: null
				}
			})
			console.log('clearAllPendingActions')
			onUpdate(delayedActions)
		},
		registerAction(actionName, handler) {
			delayedActions[actionName] = { at: null, handler, data: null }
			// console.log('registerAction', actionName)
			onUpdate(delayedActions)
			// TODO should be generic data instead of string phone
			return async (delay, phone) => {
				const msg = `Scheduled action "${actionName}" at ${delay.toLocaleString()}`
				delayedActions[actionName] = { at: delay.toLocaleString(), data: phone, handler }
				// console.log('registerAction', actionName, delay)
				onUpdate(delayedActions)
				logger.log(msg)
				sendAction({
					id: Math.random().toString(),
					type: 'Scheduler',
					state: 'completed',
					message: msg
				})
			}
		},
		triggerAction: async (actionName: string) => {
			const action = delayedActions[actionName]
			if (!action) {
				logger.error(`Action "${actionName}" not found`)
				return
			}
			const msg = `Triggered action "${actionName}" at ${new Date().toLocaleString()}`
			logger.log(msg)
			delayedActions[actionName] = { at: null, handler: action.handler, data: null }
			console.log('triggerAction', actionName)
			onUpdate(delayedActions)
			if (!action.data) {
				throw new Error('Action data is missing')
			}
			await action.handler(action.data)
		},
		serialize: () => delayedActions,
		setState: (state) => {
			for (const key in state) {
				const oldSchedule = delayedActions[key]
				if (oldSchedule) {
					delayedActions[key] = { ...oldSchedule, ...state[key] }
				}
			}
			onUpdate(delayedActions)
		}
	}
	return scheduler
}
